org.sfm.reflect.InstantiatorFactory Maven / Gradle / Ivy
package org.sfm.reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import org.sfm.map.impl.CalculateMaxIndex;
import org.sfm.map.impl.FieldKey;
import org.sfm.map.impl.PropertyMappingsBuilder;
import org.sfm.reflect.asm.AsmFactory;
import org.sfm.reflect.impl.InjectConstructorInstantiator;
import org.sfm.reflect.impl.StaticConstructorInstantiator;
public class InstantiatorFactory {
private static final Object[] EMPTY_ARGS = new Object[]{};
private final AsmFactory asmFactory;
public InstantiatorFactory(final AsmFactory asmFactory) {
this.asmFactory = asmFactory;
}
public > Instantiator getInstantiator(Type source, Type target, PropertyMappingsBuilder propertyMappingsBuilder, Map> constructorParameterGetterMap) throws NoSuchMethodException {
return getInstantiator(source, target, propertyMappingsBuilder, constructorParameterGetterMap, true);
}
public > Instantiator getInstantiator(Type source, Type target, PropertyMappingsBuilder propertyMappingsBuilder, Map> constructorParameterGetterMap, boolean useAsmIfEnabled) throws NoSuchMethodException {
if (TypeHelper.isArray(target)) {
return getArrayInstantiator(TypeHelper.toClass(TypeHelper.getComponentType(target)), propertyMappingsBuilder.forEachProperties(new CalculateMaxIndex()).maxIndex + 1);
} else {
return getInstantiator(target, TypeHelper.toClass(source), propertyMappingsBuilder.getPropertyFinder().getEligibleConstructorDefinitions(), constructorParameterGetterMap,useAsmIfEnabled);
}
}
public Instantiator getInstantiator(Type target, final Class> source, List> constructors, Map> injections, boolean useAsmIfEnabled) throws NoSuchMethodException, SecurityException {
final ConstructorDefinition constructorDefinition = getSmallerConstructor(constructors);
if (constructorDefinition == null) {
throw new IllegalArgumentException("No constructor available for " + target);
}
Constructor extends T> constructor = constructorDefinition.getConstructor();
if (asmFactory != null && Modifier.isPublic(constructor.getModifiers()) && useAsmIfEnabled) {
try {
return asmFactory.createInstatiantor(source, constructorDefinition, injections);
} catch (Exception e) {
// fall back on reflection
}
}
constructor.setAccessible(true);
if (constructor.getParameterTypes().length == 0) {
return new StaticConstructorInstantiator(constructor, EMPTY_ARGS);
} else {
return new InjectConstructorInstantiator(constructorDefinition, injections);
}
}
private ConstructorDefinition getSmallerConstructor(final List> constructors) {
ConstructorDefinition selectedConstructor = null;
for(ConstructorDefinition c : constructors) {
if (selectedConstructor == null || (c.getParameters().length < selectedConstructor.getParameters().length)) {
selectedConstructor = c;
}
}
return selectedConstructor;
}
public Instantiator getArrayInstantiator(final Class> elementType, final int length) {
return new ArrayInstantiator(elementType, length);
}
private static final class ArrayInstantiator implements Instantiator {
private final Class> elementType;
private final int length;
public ArrayInstantiator(Class> elementType, int length) {
this.elementType = elementType;
this.length = length;
}
@SuppressWarnings("unchecked")
@Override
public T newInstance(S s) throws Exception {
return (T) Array.newInstance(elementType, length);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy