
uk.co.probablyfine.inject.FemtoInjector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of femto Show documentation
Show all versions of femto Show documentation
A teeny-tiny dependency injection library
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