All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.leeonky.jfactory.SpecClassFactory Maven / Gradle / Ivy

package com.github.leeonky.jfactory;

import com.github.leeonky.util.BeanClass;
import com.github.leeonky.util.Converter;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static com.github.leeonky.util.Classes.newInstance;
import static com.github.leeonky.util.Suppressor.run;

class SpecClassFactory extends ObjectFactory {
    private final Class> specClass;
    private final Supplier> base;

    public SpecClassFactory(Class> specClass, FactorySet factorySet, boolean globalSpec) {
        super(BeanClass.create(newInstance(specClass).getType()), factorySet);
        this.specClass = specClass;
        base = guessBaseFactory(factorySet, globalSpec);
        registerTraits();
        constructor(getBase()::create);
    }

    private Supplier> guessBaseFactory(FactorySet factorySet, boolean globalSpec) {
        if (!globalSpec)
            return () -> factorySet.queryObjectFactory(getType());
        ObjectFactory typeBaseFactory = factorySet.queryObjectFactory(getType()); // DO NOT INLINE
        return () -> typeBaseFactory;
    }

    @Override
    protected Spec createSpec() {
        return newInstance(specClass);
    }

    private void registerTraits() {
        Stream.of(specClass.getMethods())
                .filter(this::isTraitMethod)
                .forEach(method -> spec(getTraitName(method), instance -> run(() ->
                        method.invoke(instance.spec(), convertParams(method, instance.traitParams())))));
    }

    private Object[] convertParams(Method method, Object[] traitParams) {
        return new ArrayList() {{
            for (int i = 0; i < method.getParameterTypes().length; i++)
                add(Converter.getInstance().convert(method.getParameterTypes()[i], traitParams[i]));
        }}.toArray();
    }

    private boolean isTraitMethod(Method method) {
        return method.getAnnotation(Trait.class) != null;
    }

    private String getTraitName(Method method) {
        Trait annotation = method.getAnnotation(Trait.class);
        return annotation.value().isEmpty() ? method.getName() : annotation.value();
    }

    @Override
    protected void collectSubSpec(Instance instance) {
        getBase().collectSpec(Collections.emptyList(), instance);
        collectClassSpec(instance, Spec::main);
    }

    protected void collectClassSpec(Instance instance, Consumer> consumer) {
        if (instance.spec().getClass().equals(specClass))
            consumer.accept(instance.spec());
        else {
            Spec spec = createSpec().setInstance(instance);
            consumer.accept(spec);
            instance.spec().append(spec);
        }
    }

    @Override
    public ObjectFactory getBase() {
        return base.get();
    }

    public Class> getSpecClass() {
        return specClass;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected Supplier fallback(String name, Supplier fallback) {
        return () -> specClass.getSuperclass().equals(Spec.class) ? getBase().queryTransformer(name, fallback)
                : factorySet.querySpecClassFactory((Class>) specClass.getSuperclass())
                .queryTransformer(name, fallback);
    }
}