CommonBuilderHandler.java

package space.sunqian.fs.object.builder.handlers;

import space.sunqian.annotation.Nonnull;
import space.sunqian.annotation.Nullable;
import space.sunqian.fs.invoke.Invocable;
import space.sunqian.fs.object.builder.BuilderOperator;
import space.sunqian.fs.object.builder.BuilderOperatorProvider;
import space.sunqian.fs.object.builder.ObjectBuilderException;
import space.sunqian.fs.reflect.TypeKit;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;

/**
 * This is the common implementation of {@link BuilderOperatorProvider.Handler}. The {@link BuilderOperator} returned by
 * this handler using the empty constructor of the target class to create the builder instance, and returns builder
 * instance itself as the final target object.
 * <p>
 * Using {@link #getInstance()} can get a same one instance of this handler.
 *
 * @author sunqian
 */
public class CommonBuilderHandler implements BuilderOperatorProvider.Handler {

    private static final @Nonnull CommonBuilderHandler INST = new CommonBuilderHandler();

    /**
     * Returns a same one instance of this handler.
     */
    public static @Nonnull CommonBuilderHandler getInstance() {
        return INST;
    }

    @Override
    public @Nullable BuilderOperator newOperator(@Nonnull Type target) throws Exception {
        Class<?> rawTarget = TypeKit.getRawClass(target);
        if (rawTarget == null) {
            return null;
        }
        try {
            Constructor<?> cst = rawTarget.getConstructor();
            return new CommonBuilderOperator(target, cst);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    private static final class CommonBuilderOperator implements BuilderOperator {

        private final @Nonnull Type targetType;
        private final @Nonnull Invocable constructor;

        private CommonBuilderOperator(
            @Nonnull Type targetType,
            @Nonnull Constructor<?> constructor
        ) {
            this.targetType = targetType;
            this.constructor = Invocable.of(constructor);
        }

        @Override
        public @Nonnull Type builderType() {
            return targetType;
        }

        @Override
        public @Nonnull Type targetType() {
            return targetType;
        }

        @Override
        public @Nonnull Object createBuilder() throws ObjectBuilderException {
            try {
                return constructor.invoke(null);
            } catch (Exception e) {
                throw new ObjectBuilderException(e);
            }
        }

        @Override
        public @Nonnull Object buildTarget(@Nonnull Object builder) throws ObjectBuilderException {
            return builder;
        }
    }
}