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.util.HashMap;
import java.util.List;
import java.util.Map;
import org.sfm.reflect.asm.AsmFactory;
import org.sfm.reflect.asm.ConstructorDefinition;
import org.sfm.reflect.asm.ConstructorParameter;
import org.sfm.reflect.impl.InjectConstructorInstantiator;
import org.sfm.reflect.impl.StaticConstructorInstantiator;
public class InstantiatorFactory {
private static final Object[] EMPTY_ARGS = new Object[]{};
@SuppressWarnings("serial")
private static final Map, Object> DEFAULT_VALUES = new HashMap, Object>() {
{
put(boolean.class, true);
put(byte.class, (byte)0);
put(char.class, (char)0);
put(short.class, (short)0);
put(int.class, 0);
put(long.class, 0l);
put(float.class, 0f);
put(double.class, 0.0);
}
};
private final AsmFactory asmFactory;
public InstantiatorFactory(final AsmFactory asmFactory) {
this.asmFactory = asmFactory;
}
public Instantiator getInstantiator(final Class source, final Class extends T> target) throws NoSuchMethodException, SecurityException {
final Constructor constructor = getSmallerConstructor(target);
if (constructor == null) {
throw new NoSuchMethodException("No available constructor for " + target);
}
Object[] args;
if (constructor.getParameterTypes().length == 0) {
if (asmFactory != null && Modifier.isPublic(constructor.getModifiers())) {
try {
return asmFactory.createEmptyArgsInstatiantor(source, target);
} catch (Exception e) {
// fall back on reflection
}
}
args = EMPTY_ARGS;
} else {
args = new Object[constructor.getParameterTypes().length];
for(int i = 0; i < args.length; i++) {
if (constructor.getParameterTypes()[i].isPrimitive()) {
args[i] = DEFAULT_VALUES.get(constructor.getParameterTypes()[i]);
}
}
}
constructor.setAccessible(true);
return new StaticConstructorInstantiator(constructor, args);
}
public Instantiator getInstantiator(final Class> source, List> constructors, Map> injections) throws NoSuchMethodException, SecurityException {
return getInstantiator(source, constructors, injections, true);
}
public Instantiator getInstantiator(final Class> source, List> constructors, Map> injections, boolean useAsmIfEnabled) throws NoSuchMethodException, SecurityException {
final ConstructorDefinition constructorDefinition = getSmallerConstructor(constructors);
Constructor 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);
}
}
@SuppressWarnings("unchecked")
private Constructor getSmallerConstructor(final Class extends T> target) {
Constructor selectedConstructor = null;
for(Constructor> c : target.getDeclaredConstructors()) {
if (selectedConstructor == null || (compare(c, selectedConstructor) < 0)) {
selectedConstructor = (Constructor) c;
}
}
return selectedConstructor;
}
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;
}
private int compare(final Constructor> c1, final Constructor> c2) {
if (Modifier.isPublic(c1.getModifiers())) {
if (Modifier.isPublic(c2.getModifiers())) {
return c1.getParameterTypes().length - c2.getParameterTypes().length;
} else {
return -1;
}
} else {
if (Modifier.isPublic(c2.getModifiers())) {
return 1;
} else {
return c1.getParameterTypes().length - c2.getParameterTypes().length;
}
}
}
public Instantiator getArrayInstantiator(final Class> elementType, final int length) {
return new Instantiator() {
@SuppressWarnings("unchecked")
@Override
public T newInstance(S s) throws Exception {
return (T) Array.newInstance(elementType, length);
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy