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

net.nokok.draft.BindingBuilder Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
package net.nokok.draft;

import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class BindingBuilder {

    private static final Logger logger = Logger.getLogger(BindingBuilder.class.getName());
    private final Class module;

    public BindingBuilder(Class module) {
        if (!module.isInterface()) {
            throw new IllegalArgumentException("Module must be interface");
        }
        this.module = Objects.requireNonNull(module);
    }

    private List getBindings(Class module) {
        if (!module.isAnnotationPresent(Module.class)) {
            return Collections.emptyList();
        }
        if (!Modifier.isPublic(module.getModifiers())) {
            logger.warning(String.format("Cannot access module %s", module));
        }
        List bindings = new ArrayList<>(module.getDeclaredMethods().length);
        for (Method method : module.getDeclaredMethods()) {
            Type[] methodGenericParameterTypes = method.getGenericParameterTypes();
            Type bindTo = method.getGenericReturnType();
            Type bindFrom;
            List qualifier;
            int parameterLength = methodGenericParameterTypes.length;
            if (parameterLength == 0) {
                bindFrom = bindTo;
                qualifier = Arrays.asList(method.getAnnotations());
            } else {
                bindFrom = methodGenericParameterTypes[0];
                qualifier = Arrays.asList(method.getParameterAnnotations()[0]);
            }
            if (method.isDefault()) {
                try {
                    ClassLoader classLoader = this.module.getClassLoader();
                    Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{this.module}, (p, m, a) -> {
                        Constructor ctor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);
                        ctor.setAccessible(true);
                        return ctor.newInstance(this.module)
                                .in(this.module)
                                .unreflectSpecial(method, this.module)
                                .bindTo(p)
                                .invokeWithArguments(new Object[parameterLength]);
                    });
                    Object result = method.invoke(proxy, new Object[parameterLength]);
                    bindings.add(new InstanceBinding(qualifier, bindFrom, bindTo, result));
                } catch (Throwable e) {
                    //invokeWithArguments throws Throwable
                    throw new RuntimeException(e);
                }
            } else {
                bindings.add(new SimpleBinding(qualifier, bindFrom, bindTo));
            }
        }
        return bindings;
    }

    public List getBindings() {
        List bindings = new ArrayList<>();
        Optional> superModuleOpt = Arrays.stream(this.module.getInterfaces()).filter(c -> c.isAnnotationPresent(Module.class)).findFirst();

        while (superModuleOpt.isPresent()) {
            Class superModule = superModuleOpt.get();
            bindings.addAll(getBindings(superModule));
            superModuleOpt = Arrays.stream(superModule.getInterfaces()).filter(c -> c.isAnnotationPresent(Module.class)).findFirst();
        }

        bindings.addAll(getBindings(this.module));
        Map bindingMap = new HashMap<>();
        bindings.forEach(b -> bindingMap.put(b.getKey(), b));

        return new ArrayList<>(bindingMap.values());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy