package org.magenta.core.injection;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.magenta.DataKey;
import org.magenta.DataSet;
import org.magenta.DataSpecification;
import org.magenta.Fixture;
import org.magenta.QualifiedDataSet;
import org.magenta.annotations.InjectDataSet;
import com.google.common.base.Supplier;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class DataSetFieldHandler<S extends DataSpecification> implements FieldInjectionHandler<S> {
@Override
public boolean handle(Field f, Object target, Supplier<Fixture<S>> current) {
if (f.isAnnotationPresent(org.magenta.annotations.InjectDataSet.class)) {
InjectDataSet annotation = f.getAnnotation(org.magenta.annotations.InjectDataSet.class);
if (DataSet.class.equals(f.getType()) || QualifiedDataSet.class.equals(f.getType())) {
DataKey key = findKey(f,annotation);
QualifiedDataSet dataset = key.qualify(supplierFor(key, current));
FieldInjectorUtils.injectInto(target, f, dataset);
return true;
}else{
throw new IllegalStateException("Annotation "+InjectDataSet.class.getName()+" is present on field named "+f.getName()+", but this field type is not a "+DataSet.class.getName());
}
} else {
return false;
}
}
private DataKey<?> findKey(Field f, InjectDataSet annotation) {
String qualifier = annotation.value();
Type gt = f.getGenericType();
if (gt instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) gt;
Type t = pt.getActualTypeArguments()[0];
if (t instanceof Class) {
Class keyType = ((Class) t);
return DataKey.makeQualified(qualifier, keyType);
} else {
throw new IllegalStateException("Dataset cannot be injected into field [" + f.getName() + "] of [" + f.getDeclaringClass()
.getName() + "] because the specified DataSet is a generic type [" + t
+ "]. A specific type should be declared such as DataSet<Integer> instead of DataSet<D>.");
}
} else {
throw new IllegalStateException(
"Dataset cannot be injected into field ["
+ f.getName()
+ "] of ["
+ f.getDeclaringClass()
.getName()
+ "] because the key cannot be derived from the DataSet since it is a rawtype. A specific type should be declared such as DataSet<Integer> instead of just DataSet.");
}
}
private Supplier<DataSet> supplierFor(final DataKey<?> key, final Supplier<Fixture<S>> current) {
return new Supplier<DataSet>() {
private DataSet cached;
private Fixture last;
private int lastVersion;
@Override
public DataSet get() {
Fixture domain = current.get();
if (domain == null) {
throw new IllegalStateException("No FixtureBuilder currently bound to the provided supplier : " + current);
}
if(cached != null && last == domain && lastVersion == domain.getVersion()){
return cached;
}
cached = domain.dataset(key);
last = domain;
lastVersion = domain.getVersion();
return cached;
}
};
}
}