package org.simpleflatmapper.reflect; import org.simpleflatmapper.reflect.instantiator.ExecutableInstantiatorDefinition; import org.simpleflatmapper.util.TypeHelper; import java.lang.reflect.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ReflectionInstantiatorDefinitionFactory { interface ParameterBuilder { Parameter[] getParameters(Method m, Type target); Parameter[] getParameters(Constructor<?> c, Type target); } public static List<InstantiatorDefinition> extractDefinitions(Type target) { if (areParameterNamePresent(target)) { return extractDefinitionsWithParamNames(target); } else { return extractDefinitionsWithoutParamNames(target); } } public static InstantiatorDefinition definition(Method m) { //IFJAVA8_START if (m.getParameters().length > 0 && m.getParameters()[0].isNamePresent()) { Parameter[] parameters = new Parameter[m.getParameters().length]; final java.lang.reflect.Parameter[] ps = m.getParameters(); for (int i = 0; i < parameters.length; i++) { parameters[i] = new Parameter(i, ps[i].getName(), ps[i].getType(), ps[i].getParameterizedType()); } return new ExecutableInstantiatorDefinition(m , parameters); } //IFJAVA8_END final Parameter[] parameters = ReflectionInstantiatorDefinitionFactory.getParameters(m, m.getGenericReturnType()); return new ExecutableInstantiatorDefinition(m, parameters); } @SuppressWarnings("unchecked") private static List<InstantiatorDefinition> extractDefinitionsWithoutParamNames(Type target) { return extractDefinitions(target, new ParameterBuilder() { @Override public Parameter[] getParameters(Method m, Type target) { return ReflectionInstantiatorDefinitionFactory.getParameters(m, target); } @Override public Parameter[] getParameters(Constructor<?> c, Type target) { return ReflectionInstantiatorDefinitionFactory.getParameters(c, target); } }); } @SuppressWarnings("unchecked") private static List<InstantiatorDefinition> extractDefinitionsWithParamNames(Type target) { return extractDefinitions(target, new ParameterBuilder() { @Override public Parameter[] getParameters(Method m, Type target) { //IFJAVA8_START if (true) { return getParametersWithName(m); } //IFJAVA8_END throw new IllegalStateException("Only supported on java8"); } @Override public Parameter[] getParameters(Constructor<?> c, Type target) { //IFJAVA8_START if (true) { return getParametersWithName(c); } //IFJAVA8_END throw new IllegalStateException("Only supported on java8"); } }); } @SuppressWarnings("unchecked") private static List<InstantiatorDefinition> extractDefinitions(Type target, ParameterBuilder parameterBuilder) { Class<?> clazz = TypeHelper.toClass(target); List<InstantiatorDefinition> instantiatorDefinitions = new ArrayList<InstantiatorDefinition>(); for(Constructor<?> constructor : clazz.getDeclaredConstructors()) { if (Modifier.isPublic(constructor.getModifiers())) { InstantiatorDefinition definition = new ExecutableInstantiatorDefinition(constructor, parameterBuilder.getParameters(constructor, target)); instantiatorDefinitions.add(definition); } } for(Method m : clazz.getDeclaredMethods()) { if (Modifier.isPublic(m.getModifiers()) && Modifier.isStatic(m.getModifiers()) && clazz.isAssignableFrom(m.getReturnType())) { InstantiatorDefinition definition = new ExecutableInstantiatorDefinition(m, parameterBuilder.getParameters(m, target)); instantiatorDefinitions.add(definition); } } return instantiatorDefinitions; } //IFJAVA8_START private static Parameter[] getParametersWithName(Executable m) { final java.lang.reflect.Parameter[] ps = m.getParameters(); Parameter[] parameters = new Parameter[ps.length]; for(int i = 0; i < parameters.length; i++) { parameters[i] = new Parameter(i, ps[i].getName(), ps[i].getType(), ps[i].getParameterizedType()); } return parameters; } //IFJAVA8_END private static Parameter[] getParameters(Constructor<?> constructor, Type target) { return buildParameters(target, constructor.getParameterTypes(), constructor.getGenericParameterTypes(), TypeHelper.toClass(target).getTypeParameters()); } private static Parameter[] getParameters(Method method, Type target) { return buildParameters(target, method.getParameterTypes(), method.getGenericParameterTypes(), TypeHelper.toClass(target).getTypeParameters()); } private static Parameter[] buildParameters(Type target, Class<?>[] parameterTypes, Type[] parameterGenericTypes, TypeVariable<Class<Object>>[] targetClassTypeParameters) { Parameter[] parameters = new Parameter[parameterTypes.length]; for(int i = 0; i < parameters.length; i++) { Type paramType = parameterGenericTypes[i]; Type resolvedParamType = null; if (paramType instanceof TypeVariable) { TypeVariable<?> tv = (TypeVariable<?>) paramType; paramType = parameterTypes[i]; if (target instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) target; int j = 0; for (TypeVariable<Class<Object>> typeParameter : targetClassTypeParameters) { if (typeParameter.getName().equals(tv.getName())) { Type[] actualTypeArguments = pt.getActualTypeArguments(); resolvedParamType = actualTypeArguments[j]; break; } j++; } } } if (resolvedParamType == null) { resolvedParamType = paramType; } parameters[i] = new Parameter(i, null, TypeHelper.toClass(paramType), resolvedParamType); } return parameters; } public static boolean areParameterNamePresent(Type target) { //IFJAVA8_START if (_areParameterNamePresent(target)) { return true; } //IFJAVA8_END return false; } //IFJAVA8_START // assume parameter name are either present or not for the type private static boolean _areParameterNamePresent(Type target) { Class<?> targetClass = TypeHelper.toClass(target); for(Method m : targetClass.getDeclaredMethods()) { final java.lang.reflect.Parameter[] parameters = m.getParameters(); if (parameters.length > 0) { return parameters[0].isNamePresent(); } } for(Constructor<?> c : targetClass.getDeclaredConstructors()) { final java.lang.reflect.Parameter[] parameters = c.getParameters(); if (parameters.length > 0) { return parameters[0].isNamePresent(); } } return false; } //IFJAVA8_END }