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

uk.co.probablyfine.inject.FemtoInjector Maven / Gradle / Ivy

The newest version!
package uk.co.probablyfine.inject;

import static java.util.Arrays.stream;
import static java.util.function.Predicate.not;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class FemtoInjector {

    private final Map, Class> boundClassToClass = new HashMap<>();
    private final Map, Object> boundClasses = new HashMap<>();

    public  T get(Class originalClass) {
        var implementingClass = (Class) implementingClass(originalClass);

        if (!boundClasses.containsKey(implementingClass)) {
            throw new InjectionException("Class [" + originalClass.getName() + "] was not bound");
        }

        if (boundClasses.getOrDefault(implementingClass, null) != null) {
            return originalClass.cast(boundClasses.get(implementingClass));
        }

        try {
            for (Constructor constructor : implementingClass.getConstructors()) {
                var parameterTypes = constructor.getParameterTypes();

                if (stream(parameterTypes)
                        .map(this::implementingClass)
                        .anyMatch(not(boundClasses::containsKey))) {
                    continue;
                }

                var instance =
                        implementingClass
                                .getConstructor(parameterTypes)
                                .newInstance(
                                        stream(parameterTypes)
                                                .map(this::loadOrCreateInstance)
                                                .toArray());

                boundClasses.put(implementingClass, instance);

                return instance;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        throw new InjectionException(
                "No injectable constructor for [" + originalClass.getName() + "]");
    }

    private Object loadOrCreateInstance(Class klazz) {
        return boundClasses.computeIfAbsent(implementingClass(klazz), this::get);
    }

    public  void bind(Class klass) {
        bind(klass, klass);
    }

    public  void bind(Class klass, T instance) {
        if (boundClasses.getOrDefault(klass, null) != null) {
            throw new InjectionException("Binding already exists for [" + klass.getName() + "]");
        }

        boundClasses.put(klass, instance);
    }

    public  void bind(Class original, Class implementation) {
        if (boundClasses.getOrDefault(implementingClass(original), null) != null) {
            throw new InjectionException("Binding already exists for [" + original.getName() + "]");
        }

        boundClassToClass.put(original, implementation);
        boundClasses.put(implementation, null);
    }

    private  Class implementingClass(Class originalClass) {
        return boundClassToClass.getOrDefault(originalClass, originalClass);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy