From b7a7fa65b85dd9866486694c4b8c87e15e0b7e5a Mon Sep 17 00:00:00 2001 From: Claudiu Soroiu Date: Thu, 29 Sep 2016 21:13:15 +0300 Subject: [PATCH] move lambda related methods at the end of the TypeResolver class (cosmetic) --- .../net/jodah/typetools/TypeResolver.java | 189 +++++++++--------- .../typetools/functional/LambdaTest.java | 12 +- 2 files changed, 101 insertions(+), 100 deletions(-) diff --git a/src/main/java/net/jodah/typetools/TypeResolver.java b/src/main/java/net/jodah/typetools/TypeResolver.java index 44edc3e..613469d 100644 --- a/src/main/java/net/jodah/typetools/TypeResolver.java +++ b/src/main/java/net/jodah/typetools/TypeResolver.java @@ -35,7 +35,7 @@ public final class TypeResolver { private static volatile boolean CACHE_ENABLED = true; private static boolean RESOLVES_LAMBDAS; private static Method GET_CONSTANT_POOL; - private static Map OBJECT_METHODS = new HashMap<>(); + private static Map OBJECT_METHODS = new HashMap(); private static final Double javaVersion; static { @@ -239,7 +239,7 @@ private static Map, Type> getTypeVariableMap(final Class targ Map, Type> map = ref != null ? ref.get() : null; if (map == null) { - map = new HashMap<>(); + map = new HashMap, Type>(); // Populate lambdas if (functionalInterface != null) @@ -271,103 +271,12 @@ private static Map, Type> getTypeVariableMap(final Class targ } if (CACHE_ENABLED) - typeVariableCache.put(targetType, new WeakReference<>(map)); + typeVariableCache.put(targetType, new WeakReference, Type>>(map)); } return map; } - /** - * Populates the {@code map} with variable/argument pairs for the {@code functionalInterface}. - */ - private static void populateLambdaArgs(Class functionalInterface, final Class lambdaType, - Map, Type> map) { - if (GET_CONSTANT_POOL != null) { - // Find SAM - for (Method m : functionalInterface.getMethods()) { - if (!isDefaultMethod(m) && !Modifier.isStatic(m.getModifiers()) && !m.isBridge()) { - // Skip methods that override Object.class - Method objectMethod = OBJECT_METHODS.get(m.getName()); - if (objectMethod != null && Arrays.equals(m.getTypeParameters(), objectMethod.getTypeParameters())) - continue; - - // Get functional interface's type params - Type returnTypeVar = m.getGenericReturnType(); - Type[] paramTypeVars = m.getGenericParameterTypes(); - - Method methodInfo; - try { - methodInfo = getMethodInfo((ConstantPool) GET_CONSTANT_POOL.invoke(lambdaType)); - if (methodInfo == null) { - return; - } - } catch (Exception e) { - return; - } - - // Populate return type argument - if (returnTypeVar instanceof TypeVariable) { - Class returnType = methodInfo.getReturnType(); - returnType = wrapPrimitives(returnType); - if (!returnType.equals(Void.class)) { - map.put((TypeVariable) returnTypeVar, returnType); - } - } - - Class[] arguments = methodInfo.getParameterTypes(); - - // Populate object type from arbitrary object method reference - int paramOffset = 0; - if (paramTypeVars.length > 0 && paramTypeVars[0] instanceof TypeVariable - && paramTypeVars.length == arguments.length + 1) { - Class instanceType = methodInfo.getDeclaringClass(); - map.put((TypeVariable) paramTypeVars[0], instanceType); - paramOffset = 1; - } - - // Handle additional arguments that are captured from the lambda's enclosing scope - int argOffset = 0; - if (paramTypeVars.length < arguments.length) { - argOffset = arguments.length - paramTypeVars.length; - } - - // Populate type arguments - for (int i = 0; i + argOffset < arguments.length; i++) { - if (paramTypeVars[i] instanceof TypeVariable) { - map.put((TypeVariable) paramTypeVars[i + paramOffset], - wrapPrimitives(arguments[i + argOffset])); - } - } - - return; - } - } - } - } - - private static final Map, Class> primitives; - static { - HashMap, Class> types = new HashMap<>(); - types.put(boolean.class, Boolean.class); - types.put(byte.class, Byte.class); - types.put(char.class, Character.class); - types.put(double.class, Double.class); - types.put(float.class, Float.class); - types.put(int.class, Integer.class); - types.put(long.class, Long.class); - types.put(short.class, Short.class); - types.put(void.class, Void.class); - primitives = Collections.unmodifiableMap(types); - } - - private static Class wrapPrimitives(Class clazz) { - return clazz.isPrimitive()? primitives.get(clazz): clazz; - } - - private static boolean isDefaultMethod(Method m) { - return javaVersion >= 1.8 && m.isDefault(); - } - /** * Populates the {@code map} with with variable/argument pairs for the given {@code types}. */ @@ -447,12 +356,85 @@ public static Type resolveBound(TypeVariable typeVariable) { return bound == Object.class ? Unknown.class : bound; } + /** + * Populates the {@code map} with variable/argument pairs for the {@code functionalInterface}. + */ + private static void populateLambdaArgs(Class functionalInterface, final Class lambdaType, + Map, Type> map) { + if (GET_CONSTANT_POOL != null) { + // Find SAM + for (Method m : functionalInterface.getMethods()) { + if (!isDefaultMethod(m) && !Modifier.isStatic(m.getModifiers()) && !m.isBridge()) { + // Skip methods that override Object.class + Method objectMethod = OBJECT_METHODS.get(m.getName()); + if (objectMethod != null && Arrays.equals(m.getTypeParameters(), objectMethod.getTypeParameters())) + continue; + + // Get functional interface's type params + Type returnTypeVar = m.getGenericReturnType(); + Type[] paramTypeVars = m.getGenericParameterTypes(); + + Method methodInfo; + try { + methodInfo = getMethodInfo((ConstantPool) GET_CONSTANT_POOL.invoke(lambdaType)); + if (methodInfo == null) { + return; + } + } catch (Exception ignore) { + return; + } + + // Populate return type argument + if (returnTypeVar instanceof TypeVariable) { + Class returnType = methodInfo.getReturnType(); + returnType = wrapPrimitives(returnType); + if (!returnType.equals(Void.class)) { + map.put((TypeVariable) returnTypeVar, returnType); + } + } + + Class[] arguments = methodInfo.getParameterTypes(); + + // Populate object type from arbitrary object method reference + int paramOffset = 0; + if (paramTypeVars.length > 0 && paramTypeVars[0] instanceof TypeVariable + && paramTypeVars.length == arguments.length + 1) { + Class instanceType = methodInfo.getDeclaringClass(); + map.put((TypeVariable) paramTypeVars[0], instanceType); + paramOffset = 1; + } + + // Handle additional arguments that are captured from the lambda's enclosing scope + int argOffset = 0; + if (paramTypeVars.length < arguments.length) { + argOffset = arguments.length - paramTypeVars.length; + } + + // Populate type arguments + for (int i = 0; i + argOffset < arguments.length; i++) { + if (paramTypeVars[i] instanceof TypeVariable) { + map.put((TypeVariable) paramTypeVars[i + paramOffset], + wrapPrimitives(arguments[i + argOffset])); + } + } + + return; + } + } + } + } + + private static boolean isDefaultMethod(Method m) { + return javaVersion >= 1.8 && m.isDefault(); + } + private static Method getMethodInfo(ConstantPool constantPool) { Method returnValue = null; for (int i = constantPool.getSize() - 1; i >= 0; i--) { try { Member member = constantPool.getMethodAt(i); + //skip constructors if (!(member instanceof Method)) { continue; } @@ -468,4 +450,23 @@ private static Method getMethodInfo(ConstantPool constantPool) { return returnValue; } + + private static final Map, Class> primitives; + static { + HashMap, Class> types = new HashMap, Class>(); + types.put(boolean.class, Boolean.class); + types.put(byte.class, Byte.class); + types.put(char.class, Character.class); + types.put(double.class, Double.class); + types.put(float.class, Float.class); + types.put(int.class, Integer.class); + types.put(long.class, Long.class); + types.put(short.class, Short.class); + types.put(void.class, Void.class); + primitives = Collections.unmodifiableMap(types); + } + + private static Class wrapPrimitives(Class clazz) { + return clazz.isPrimitive()? primitives.get(clazz): clazz; + } } diff --git a/src/test/java/net/jodah/typetools/functional/LambdaTest.java b/src/test/java/net/jodah/typetools/functional/LambdaTest.java index cd93b25..c867229 100644 --- a/src/test/java/net/jodah/typetools/functional/LambdaTest.java +++ b/src/test/java/net/jodah/typetools/functional/LambdaTest.java @@ -23,7 +23,7 @@ /** * Tests the resolution of type arguments defined on lambda expressions. - * + * * @author Jonathan Halterman */ @Test @@ -44,15 +44,15 @@ interface ReverseFn extends Function { } interface SelectingFn extends ReverseFn { - }; + } interface StrToInt extends SelectingFn { - }; + } interface SerializableFn extends Function, Serializable { - }; + } - public static interface Function3 { + public interface Function3 { R apply(T t, U u, V v); } @@ -176,7 +176,7 @@ public void shouldResolveArgumentsFromNonSamMethodRef() throws Throwable { /** * Asserts that method references with primitive type arguments that are auto boxed to primitive wrappers are properly * handled. - * + * * Note: disabled since method signature exposed via constant pool contains convert(String, Object). Subsequent * bytecode contains convert(String, String). May need ASM to read. */