package com.softwaremill.common.util;
import com.google.common.base.Predicates;
import org.reflections.ReflectionUtils;
import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class CDIInjector<T> {
private final T target;
private CDIInjector(T target) {
this.target = target;
}
public T get() {
return target;
}
public CDIInjector<T> inject(Object... objects) {
for (Object obj : objects) {
doInject(null, obj);
}
return this;
}
public CDIInjector<T> injectWithQualifier(Class<? extends Annotation> qualifier, Object obj) {
doInject(qualifier, obj);
return this;
}
private void doInject(Class<? extends Annotation> qualifier, Object obj) {
if (obj == null) {
return;
}
for (Field field : ReflectionUtils.getAllFields(target.getClass(), Predicates.alwaysTrue())) {
if (fieldIsInjectable(field) &&
fieldTypeAssignableFrom(field, obj.getClass()) &&
fieldHasQualifier(field, qualifier)) {
checkFieldNotYetAssigned(field);
new RichObject(target).set(field.getName(), obj);
return;
}
}
throw new IllegalStateException("Cannot inject " + obj + ": no sutiable field found in " + target);
}
private void checkFieldNotYetAssigned(Field field) {
Object currentValue = new RichObject(target).get(field.getName());
if (currentValue != null) {
throw new IllegalStateException("Field " + field.getName() + " in object " + target +
" already has a value: " + currentValue);
}
}
private boolean fieldIsInjectable(Field field) {
return field.getAnnotation(Inject.class) != null;
}
private boolean fieldHasQualifier(Field field, Class<? extends Annotation> qualifier) {
return qualifier == null || field.getAnnotation(qualifier) != null;
}
private boolean fieldTypeAssignableFrom(Field field, Class<?> cls) {
return field.getType().isAssignableFrom(cls);
}
public static <T> CDIInjector<T> into(T target) {
return new CDIInjector<T>(target);
}
}