Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.simpleflatmapper.reflect.asm.BiInstantiatorBuilder Maven / Gradle / Ivy
package org.simpleflatmapper.reflect.asm;
import org.simpleflatmapper.ow2asm.ClassWriter;
import org.simpleflatmapper.ow2asm.FieldVisitor;
import org.simpleflatmapper.ow2asm.Label;
import org.simpleflatmapper.ow2asm.MethodVisitor;
import org.simpleflatmapper.ow2asm.Opcodes;
import org.simpleflatmapper.reflect.BiInstantiator;
import org.simpleflatmapper.reflect.BuilderInstantiatorDefinition;
import org.simpleflatmapper.reflect.Getter;
import org.simpleflatmapper.reflect.Instantiator;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.reflect.Parameter;
import org.simpleflatmapper.reflect.getter.BiFunctionGetter;
import org.simpleflatmapper.reflect.instantiator.ExecutableInstantiatorDefinition;
import org.simpleflatmapper.reflect.primitive.BooleanGetter;
import org.simpleflatmapper.reflect.primitive.ByteGetter;
import org.simpleflatmapper.reflect.primitive.CharacterGetter;
import org.simpleflatmapper.reflect.primitive.DoubleGetter;
import org.simpleflatmapper.reflect.primitive.FloatGetter;
import org.simpleflatmapper.reflect.primitive.IntGetter;
import org.simpleflatmapper.reflect.primitive.LongGetter;
import org.simpleflatmapper.reflect.primitive.ShortGetter;
import org.simpleflatmapper.util.BiFunction;
import org.simpleflatmapper.util.Consumer;
import org.simpleflatmapper.util.TypeHelper;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static org.simpleflatmapper.ow2asm.Opcodes.ACC_BRIDGE;
import static org.simpleflatmapper.ow2asm.Opcodes.ACC_FINAL;
import static org.simpleflatmapper.ow2asm.Opcodes.ACC_PUBLIC;
import static org.simpleflatmapper.ow2asm.Opcodes.ACC_SUPER;
import static org.simpleflatmapper.ow2asm.Opcodes.ACC_SYNTHETIC;
import static org.simpleflatmapper.ow2asm.Opcodes.ACONST_NULL;
import static org.simpleflatmapper.ow2asm.Opcodes.ALOAD;
import static org.simpleflatmapper.ow2asm.Opcodes.ARETURN;
import static org.simpleflatmapper.ow2asm.Opcodes.ASTORE;
import static org.simpleflatmapper.ow2asm.Opcodes.CHECKCAST;
import static org.simpleflatmapper.ow2asm.Opcodes.DUP;
import static org.simpleflatmapper.ow2asm.Opcodes.GETFIELD;
import static org.simpleflatmapper.ow2asm.Opcodes.IFNULL;
import static org.simpleflatmapper.ow2asm.Opcodes.INVOKEINTERFACE;
import static org.simpleflatmapper.ow2asm.Opcodes.INVOKESPECIAL;
import static org.simpleflatmapper.ow2asm.Opcodes.INVOKESTATIC;
import static org.simpleflatmapper.ow2asm.Opcodes.INVOKEVIRTUAL;
import static org.simpleflatmapper.ow2asm.Opcodes.NEW;
import static org.simpleflatmapper.ow2asm.Opcodes.PUTFIELD;
import static org.simpleflatmapper.ow2asm.Opcodes.RETURN;
import static org.simpleflatmapper.ow2asm.Opcodes.V1_6;
public class BiInstantiatorBuilder {
public static final Class BI_INSTANTIATOR_CLASS = BiInstantiator.class;
public static final Class INSTANTIATOR_CLASS = Instantiator.class;
public static final String BI_FUNCTION_PREFIX = "factory_";
public static byte[] createInstantiator(final String className, final Class s1, final Class s2,
final ExecutableInstantiatorDefinition instantiatorDefinition, final Map> injectionsMap) throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
Class targetClass= TypeHelper.toClass(getTargetType(instantiatorDefinition));
String targetType = AsmUtils.toAsmType(targetClass);
String s1Type = AsmUtils.toWrapperType(s1);
String s2Type = AsmUtils.toWrapperType(s2);
String classType = AsmUtils.toAsmType(className);
String instantiatorType = AsmUtils.toAsmType(BI_INSTANTIATOR_CLASS);
List injections = toInjections(injectionsMap);
cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "Ljava/lang/Object;L" + instantiatorType + ";", "java/lang/Object",
new String[] { instantiatorType });
Parameter[] parameters = instantiatorDefinition.getParameters();
appendFunctionsField(injections, cw);
appendInit(injections, cw, s1Type, s2Type, classType);
appendNewInstance(s1, s2, instantiatorDefinition, injections, cw, targetType, s1Type, s2Type, classType, parameters);
appendBridgeMethod(cw, targetType, s1Type, s2Type, classType);
appendToString(injections, cw, parameters);
cw.visitEnd();
return AsmUtils.writeClassToFile(className, cw.toByteArray());
}
private static List toInjections(Map> injectionsMap) {
List injections = new ArrayList(injectionsMap.size());
for(Entry> e : injectionsMap.entrySet()) {
injections.add(getFunctionCall(e.getKey(), e.getValue()));
}
return injections;
}
public static byte[] createInstantiator(final String className, final Class s1, final Class s2,
final Instantiator builderInstantiator,
final BuilderInstantiatorDefinition instantiatorDefinition,
final Map> injectionsMap, boolean ignoreNullValues) throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES );
Class targetClass= TypeHelper.toClass(getTargetType(instantiatorDefinition));
String targetType = AsmUtils.toAsmType(targetClass);
String s1Type = AsmUtils.toWrapperType(s1);
String s2Type = AsmUtils.toWrapperType(s2);
String classType = AsmUtils.toAsmType(className);
String instantiatorType = AsmUtils.toAsmType(BI_INSTANTIATOR_CLASS);
List injections = toInjections(injectionsMap);
cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "Ljava/lang/Object;L" + instantiatorType + ";", "java/lang/Object",
new String[] { instantiatorType });
{
FieldVisitor fv =
cw.visitField(
ACC_FINAL,
"builderInstantiator",
"L" + AsmUtils.toAsmType(INSTANTIATOR_CLASS) + ";",
"L" + AsmUtils.toAsmType(INSTANTIATOR_CLASS) + ";", null);
fv.visitEnd();
}
appendFunctionsField(injections, cw);
appendInitBuilder(injections, cw, s1Type, s2Type, classType, instantiatorDefinition);
appendNewInstanceBuilder(s1, s2, instantiatorDefinition, injections, cw, targetType, s1Type, s2Type, classType, instantiatorDefinition.getSetters(), ignoreNullValues);
appendBridgeMethod(cw, targetType, s1Type, s2Type, classType);
appendToString(injections, cw, instantiatorDefinition.getParameters());
cw.visitEnd();
return AsmUtils.writeClassToFile(className, cw.toByteArray());
}
private static void appendFunctionsField(List injections, ClassWriter cw) {
for(InjectionPoint injectionPoint : injections) {
FieldVisitor fv = cw.visitField(ACC_FINAL, getBiFunctionFieldName(injectionPoint.parameter), AsmUtils.toTargetTypeDeclaration(injectionPoint.functionType), null, null);
fv.visitEnd();
}
}
private static void appendInit(List injections, ClassWriter cw, String s1, String s2, String classType) {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, "",
"(Ljava/util/Map;)V",
"(Ljava/util/Map;>;)V", null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
appendInitField(injections, classType, mv);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 2);
mv.visitEnd();
}
private static void appendInitBuilder(List injections, ClassWriter cw, String s1, String s2, String classType, BuilderInstantiatorDefinition instantiatorDefinition) {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, "",
"(Ljava/util/Map;L" + AsmUtils.toAsmType(INSTANTIATOR_CLASS) + ";)V",
"(Ljava/util/Map;>;" +
"L" + AsmUtils.toAsmType(INSTANTIATOR_CLASS) + ";)V", null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitFieldInsn(PUTFIELD, classType, "builderInstantiator", "L" + AsmUtils.toAsmType(INSTANTIATOR_CLASS) + ";");
appendInitField(injections, classType, mv);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 2);
mv.visitEnd();
}
private static void appendInitField(List injections, String classType, MethodVisitor mv) {
for(InjectionPoint injectionPoint : injections) {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn(injectionPoint.parameter.getName());
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
if (injectionPoint.isGetter) {
mv.visitTypeInsn(CHECKCAST, AsmUtils.toAsmType(BiFunctionGetter.class));
mv.visitMethodInsn(INVOKEVIRTUAL, AsmUtils.toAsmType(BiFunctionGetter.class), "getGetter", "()" + AsmUtils.toTargetTypeDeclaration(Getter.class), false);
}
mv.visitTypeInsn(CHECKCAST, AsmUtils.toAsmType(injectionPoint.functionType));
mv.visitFieldInsn(PUTFIELD, classType, getBiFunctionFieldName(injectionPoint.parameter), AsmUtils.toTargetTypeDeclaration(injectionPoint.functionType));
}
}
private static void appendNewInstance(Class s1, Class s2, ExecutableInstantiatorDefinition instantiatorDefinition, List injectionPoints, ClassWriter cw, String targetType, String s1Type, String s2Type, String classType, Parameter[] parameters) throws NoSuchMethodException {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "(" + AsmUtils.toTargetTypeDeclaration(s1Type) + AsmUtils.toTargetTypeDeclaration(s2Type) +")" + AsmUtils.toTargetTypeDeclaration(targetType), null, new String[] { "java/lang/Exception" });
mv.visitCode();
if (!Modifier.isStatic(instantiatorDefinition.getExecutable().getModifiers())) {
mv.visitTypeInsn(NEW, targetType);
mv.visitInsn(DUP);
}
StringBuilder sb = new StringBuilder();
for (Parameter p : parameters) {
final InjectionPoint function = findFunctionCalls(p, injectionPoints);
sb.append(AsmUtils.toTargetTypeDeclaration(p.getType()));
if (function == null) {
newInstanceNullFunction(mv, p);
} else {
invokeBiFunction(targetType, function, classType, s1, s2, mv, new Consumer() {
@Override
public void accept(MethodVisitor mv) {
mv.visitVarInsn(AsmUtils.getLoadOps(function.parameter.getType()), 4);
}
}, false);
}
}
Member exec = instantiatorDefinition.getExecutable();
if (exec instanceof Constructor) {
mv.visitMethodInsn(INVOKESPECIAL, targetType, "", "(" + sb.toString() + ")V", false);
} else {
mv.visitMethodInsn(INVOKESTATIC, AsmUtils.toAsmType(((Method)exec).getDeclaringClass()), exec.getName(),
AsmUtils.toSignature((Method)exec)
, false);
}
mv.visitInsn(ARETURN);
mv.visitMaxs(3 , 2);
mv.visitEnd();
}
private static void appendNewInstanceBuilder(Class s1, Class s2, BuilderInstantiatorDefinition instantiatorDefinition, List injectionPoints, ClassWriter cw, String targetType, String s1Type, String s2Type, String classType, Map setters, boolean ignoreNullValues) throws NoSuchMethodException {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "(" + AsmUtils.toTargetTypeDeclaration(s1Type) + AsmUtils.toTargetTypeDeclaration(s2Type)+ ")" + AsmUtils.toTargetTypeDeclaration(targetType), null, new String[] { "java/lang/Exception" });
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD,classType, "builderInstantiator", AsmUtils.toTargetTypeDeclaration(INSTANTIATOR_CLASS));
mv.visitInsn(ACONST_NULL);
mv.visitMethodInsn(INVOKEINTERFACE, AsmUtils.toAsmType(INSTANTIATOR_CLASS), "newInstance", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
final Type builderClass = getTargetType(instantiatorDefinition.getBuilderInstantiator());
final String builderType = AsmUtils.toAsmType(builderClass);
mv.visitTypeInsn(CHECKCAST, builderType);
mv.visitVarInsn(ASTORE, 3);
for (final Entry e : setters.entrySet()) {
Parameter p = e.getKey();
final InjectionPoint injectionPoint = findFunctionCalls(p, injectionPoints);
if (injectionPoint != null) {
final boolean checkIfNull = ignoreNullValues && !injectionPoint.isPrimitive;
invokeBiFunction(targetType, injectionPoint, classType, s1, s2, mv,
new Consumer() {
@Override
public void accept(MethodVisitor mv) {
mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(AsmUtils.getLoadOps(injectionPoint.parameter.getType()), 4);
AsmUtils.invoke(mv, TypeHelper.toClass(builderClass), e.getValue().getName(),
AsmUtils.toSignature(e.getValue()));
if (!Void.TYPE.equals(e.getValue().getReturnType())) {
if(!e.getValue().getReturnType().equals(builderClass)) {
mv.visitTypeInsn(CHECKCAST, builderType);
}
mv.visitVarInsn(ASTORE, 3);
}
}
}, ignoreNullValues);
}
}
mv.visitVarInsn(ALOAD, 3);
Method buildMethod = instantiatorDefinition.getBuildMethod();
if (Modifier.isStatic(buildMethod.getModifiers())) {
mv.visitMethodInsn(INVOKESTATIC,
AsmUtils.toAsmType(buildMethod.getDeclaringClass()),
buildMethod.getName(), AsmUtils.toSignature(buildMethod), false);
} else {
AsmUtils.invoke(mv, TypeHelper.toClass(builderClass),
buildMethod.getName(),
AsmUtils.toSignature(buildMethod));
}
mv.visitInsn(ARETURN);
mv.visitMaxs(3 , 2);
mv.visitEnd();
}
private static InjectionPoint findFunctionCalls(Parameter p, List injectionPoints) {
for(InjectionPoint fc : injectionPoints) {
if (fc.parameter.equals(p)) {
return fc;
}
}
return null;
}
private static void newInstanceNullFunction(MethodVisitor mv, Parameter p) {
if (TypeHelper.isPrimitive(p.getType())) {
mv.visitInsn(AsmUtils.defaultValue.get(p.getType()));
} else {
mv.visitInsn(ACONST_NULL);
}
}
private static void invokeBiFunction(String targetType, InjectionPoint injectionPoint, String classType, Class s1, Class s2, MethodVisitor mv, Consumer consumer, boolean ignoreNullValues) throws NoSuchMethodException {
String s1Type = AsmUtils.toAsmType(s1.equals(Void.class) || s1.equals(void.class) ? Object.class : s1);
String s2Type = AsmUtils.toAsmType(s2.equals(Void.class) || s2.equals(void.class) ? Object.class : s2);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, classType, getBiFunctionFieldName(injectionPoint.parameter), AsmUtils.toTargetTypeDeclaration(injectionPoint.functionType));
mv.visitVarInsn(ALOAD, 1);
if (!injectionPoint.isGetter){
mv.visitVarInsn(ALOAD, 2);
}
Method getterMethod = injectionPoint.getMethod();
AsmUtils.invoke(mv, getterMethod);
if (!injectionPoint.isPrimitive) {
// IF NULL
Class wrapperClass = AsmUtils.toWrapperClass(injectionPoint.parameter.getType());
if (!wrapperClass.isAssignableFrom(getterMethod.getReturnType())) {
mv.visitTypeInsn(CHECKCAST, AsmUtils.toAsmType(wrapperClass));
}
mv.visitVarInsn(ASTORE, 4);
Label label = new Label();
if (ignoreNullValues) {
mv.visitVarInsn(ALOAD, 4);
mv.visitJumpInsn(IFNULL, label);
}
changeToPrimitiveIfNeeded(injectionPoint, mv, wrapperClass, ignoreNullValues);
if (consumer != null) {
consumer.accept(mv);
}
if (ignoreNullValues) {
mv.visitLabel(label);
if (injectionPoint.isGetter) {
mv.visitFrame(Opcodes.F_APPEND, 2, new Object[]{AsmUtils.toAsmType(targetType), AsmUtils.toAsmType(wrapperClass) }, 0, null);
} else {
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{AsmUtils.toAsmType(wrapperClass)}, 0, null);
}
}
// iframe?
} else {
mv.visitVarInsn(AsmUtils.getStoreOps(injectionPoint.parameter.getType()), 4);
if (consumer != null) {
consumer.accept(mv);
}
}
}
private static void changeToPrimitiveIfNeeded(InjectionPoint injectionPoint, MethodVisitor mv, Class wrapperClass, boolean ignoreNullValues) {
if (TypeHelper.isPrimitive(injectionPoint.parameter.getType())) {
mv.visitVarInsn(ALOAD, 4);
String methodSuffix = getPrimitiveMethodSuffix(injectionPoint.parameter);
String valueMethodPrefix = methodSuffix.toLowerCase();
if ("character".equals(valueMethodPrefix)) {
valueMethodPrefix = "char";
}
String valueMethod = valueMethodPrefix + "Value";
AsmUtils.invoke(mv, wrapperClass, valueMethod, "()" + AsmUtils.toAsmType(injectionPoint.parameter.getType()));
mv.visitVarInsn(AsmUtils.getStoreOps(injectionPoint.parameter.getType()), 4);
}
}
private static String getBiFunctionFieldName(Parameter p) {
return BI_FUNCTION_PREFIX + p.getName();
}
private static String getPrimitiveMethodSuffix(Parameter p) {
return getPrimitiveMethodSuffix(p.getType());
}
private static String getPrimitiveMethodSuffix(Class type) {
String methodSuffix = AsmUtils.wrappers.get(type).getSimpleName();
if ("Integer".equals(methodSuffix)) {
methodSuffix = "Int";
}
return methodSuffix;
}
private static void appendBridgeMethod(ClassWriter cw, String targetType, String s1Type, String s2Type,String classType) {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC,
"newInstance", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null,
new String[] { "java/lang/Exception" });
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, s1Type);
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, s2Type);
mv.visitMethodInsn(INVOKEVIRTUAL, classType, "newInstance", "(" + AsmUtils.toTargetTypeDeclaration(s1Type) + AsmUtils.toTargetTypeDeclaration(s2Type) +")"
+ AsmUtils.toTargetTypeDeclaration(targetType), false);
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
private static void appendToString(List injections, ClassWriter cw, Parameter[] parameters) {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false);
mv.visitVarInsn(ASTORE, 1);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getSimpleName", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitLdcInsn("{");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
for(int i = 0; i < parameters.length; i++) {
String paramName = (i > 0 ? ", " : "") + "parameter" + i + "=";
String parameter = String.valueOf(parameters[i]);
mv.visitLdcInsn(paramName);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitLdcInsn(parameter);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
InjectionPoint injectionPoint = findFunctionCalls(parameters[i], injections);
String getterName = ", parameter" + i + "=";
String getterString = injectionPoint != null ? injectionPoint.functionType.toString() : "";
mv.visitLdcInsn(getterName);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitLdcInsn(getterString);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
}
mv.visitLdcInsn("}");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
private static InjectionPoint getFunctionCall(Parameter parameter, BiFunction biFunction) {
if (biFunction.getClass().equals(BiFunctionGetter.class)) {
Getter getter = ((BiFunctionGetter)biFunction).getGetter();
Class getterClass = getter.getClass();
if (TypeHelper.isPrimitive(parameter.getType())) {
Class primitiveGetter = getPrimitiveGetter(parameter.getType());
if (primitiveGetter == null) {
throw new IllegalStateException("No primitive getter for primitive " + parameter.getType());
}
Type publicGetterClass = AsmUtils.findClosestPublicTypeExposing(getterClass, primitiveGetter);
if (publicGetterClass != null) {
return new InjectionPoint(parameter, biFunction, true, "get" + getPrimitiveMethodSuffix(parameter.getType()), publicGetterClass, true);
}
}
Type publicGetterClass = AsmUtils.findClosestPublicTypeExposing(getterClass, Getter.class);
return new InjectionPoint(parameter, biFunction, true, "get", publicGetterClass, false);
} else {
return new InjectionPoint(parameter, biFunction, false, "apply", biFunction.getClass(), false);
}
}
public static Type getTargetType(InstantiatorDefinition instantiatorDefinition) {
switch (instantiatorDefinition.getType()) {
case METHOD:
return ((Method)((ExecutableInstantiatorDefinition)instantiatorDefinition).getExecutable()).getGenericReturnType();
case CONSTRUCTOR:
return ((Constructor)((ExecutableInstantiatorDefinition)instantiatorDefinition).getExecutable()).getDeclaringClass();
case BUILDER:
return ((BuilderInstantiatorDefinition)instantiatorDefinition).getBuildMethod().getGenericReturnType();
default:
throw new IllegalArgumentException("Unsupported type " + instantiatorDefinition.getType());
}
}
static final Map, Class> primitivesGetter = new HashMap, Class>();
static {
primitivesGetter.put(boolean.class, BooleanGetter.class);
primitivesGetter.put(byte.class, ByteGetter.class);
primitivesGetter.put(char.class, CharacterGetter.class);
primitivesGetter.put(short.class, ShortGetter.class);
primitivesGetter.put(int.class, IntGetter.class);
primitivesGetter.put(long.class, LongGetter.class);
primitivesGetter.put(float.class, FloatGetter.class);
primitivesGetter.put(double.class, DoubleGetter.class);
}
public static Class getPrimitiveGetter(Class propertyType) {
return primitivesGetter.get(propertyType);
}
static class InjectionPoint {
final Parameter parameter;
final BiFunction function;
final boolean isGetter;
final String methodName;
final Type functionType;
final boolean isPrimitive;
InjectionPoint(Parameter parameter, BiFunction function, boolean isGetter, String methodName, Type functionType, boolean isPrimitive) {
this.parameter = parameter;
this.function = function;
this.isGetter = isGetter;
this.methodName = methodName;
this.functionType = functionType;
this.isPrimitive = isPrimitive;
}
public Method getMethod() {
return BiInstantiatorBuilder.getMethod(TypeHelper.toClass(functionType), methodName, isGetter ? 1 : 2);
}
}
public static Method getMethod(Class aClass, String name, int nbParam) {
Method m = null;
for(Method p : aClass.getDeclaredMethods()) {
if (!Modifier.isStatic(p.getModifiers())
&& p.getName().equals(name)
&& (p.getParameterTypes() != null && p.getParameterTypes().length == nbParam)) {
// crude way of selecting non bridge method
if (m == null || p.getModifiers() < m.getModifiers()) {
m = p;
}
}
}
return m;
}
}