ConfigurationClassContext.java

package fi.eis.libraries.di;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConfigurationClassContext extends Context {
    private final Map<Class, Object> classObjectMap = new HashMap<>();

    public ConfigurationClassContext(Class... configurationClasses) {
        this(SimpleLogger.LogLevel.NONE, configurationClasses);
    }
    public ConfigurationClassContext(SimpleLogger.LogLevel logLevel, Class... configurationClassInstances) {
        setLogLevel(logLevel);

        try {
            List<Map.Entry<Object, Method>> confClassCreationMethodTuples = new ArrayList<>();
            for (Class configurationClass: configurationClassInstances){
                Object configurationClassInstance = configurationClass.newInstance();

                for (Method m : Arrays.asList(configurationClass.getMethods())) {
                    if (m.getDeclaringClass() != Object.class) {
                        logger.debug("Got method " + m);
                        confClassCreationMethodTuples.add(tuple(configurationClassInstance, m));
                    }
                }
            }
            Collections.sort(confClassCreationMethodTuples, ConfClassCreationMethodTuplesComparator);
            logger.debug("tuples: " + confClassCreationMethodTuples);

            for (Map.Entry<Object,Method> confClassCreationMethodTuple: confClassCreationMethodTuples) {
                Method method = confClassCreationMethodTuple.getValue();
                Object instance = newInstance(confClassCreationMethodTuple.getKey(), method);
                classObjectMap.put(method.getReturnType(), instance);
                logger.debug("instantiated and stored instance for class " + method.getReturnType());
            }
        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            throw new IllegalArgumentException(e);
        }
        logger.debug("class-instance module: " + DependencyInjection.classesWithInstances(classObjectMap));
        super.modules.add(DependencyInjection.classesWithInstances(classObjectMap)) ;
    }

    private static Map.Entry<Object,Method> tuple(Object object, Method method) {
        return new HashMap.SimpleEntry<>(object, method);
    }
    private static final Comparator<Map.Entry<Object,Method>> ConfClassCreationMethodTuplesComparator = new Comparator<Map.Entry<Object, Method>>() {
        @Override
        public int compare(Map.Entry<Object, Method> o1, Map.Entry<Object, Method> o2) {
            return Integer.compare(o1.getValue().getParameterTypes().length, o2.getValue().getParameterTypes().length);
        }
    };

    private Object newInstance(Object configurationClass, Method method) throws InstantiationException,
            IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class[] parameterTypes = method.getParameterTypes();
        Object[] paramArr = new Object[parameterTypes.length];
        int i = 0;

        for(Class c : parameterTypes) {
            paramArr[i++] = classObjectMap.get(c);
        }
        return method.invoke(configurationClass, paramArr);
    }
}