FULL PRODUCT VERSION : java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode) ADDITIONAL OS VERSION INFORMATION : Linux omen 4.8.14-200.fc24.x86_64 #1 SMP Mon Dec 12 16:31:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux A DESCRIPTION OF THE PROBLEM : Unlike generically typed anonymous classes, generically typed lambda expressions do not preserve type variable information at runtime. For example, public interface ContextResolver<T> { T getContext(Class<?> type); } @Test public void test() { ContextResolver<String> resolver = ((ContextResolver<String>)type -> "foo"); for (Type type : resolver.getClass().getGenericInterfaces()) { System.out.println("type: " + type); } } outputs type: interface javax.ws.rs.ext.ContextResolver but running @Test public void test() { ContextResolver<String> resolver1 = new ContextResolver<String>() { @Override public String getContext(Class<?> type) { return null; } }; for (Type type : resolver.getClass().getGenericInterfaces()) { System.out.println("type: " + type); } } outputs type: javax.ws.rs.ext.ContextResolver<java.lang.String> There is a known solution to this problem, found here: https://github.com/jhalterman/typetools (specifically, in TypeResolver, here: https://github.com/jhalterman/typetools/blob/master/src/main/java/net/jodah/typetools/TypeResolver.java). One problem seems to be the reference to a java.sun class: String constantPoolName = JAVA_VERSION < 9 ? "sun.reflect.ConstantPool" : "jdk.internal.reflect.ConstantPool"; Note that the fix works for * java-1.8.0-openjdk-1.8.0.121-8.b14.fc24.x86_64 * jdk1.8.0_121 (oracle: build 25.121-b13) * openjdk 9 (build 9-ea+163) but it doesn't work for * ibm JRE 1.8.0 (build 2.8) STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Just run the example above. EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - javax.ws.rs.ext.ContextResolver<java.lang.String> ACTUAL - type: interface javax.ws.rs.ext.ContextResolver REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- public class ContextResolverTest { public static void main(String[] args) { ContextResolver<String> resolver = ((ContextResolver<String>)type -> "foo"); for (Type type : resolver.getClass().getGenericInterfaces()) { System.out.println("type: " + type); } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : With some JDKs, it's possible to use the above mentioned TypeResolver to retrieve the value of type variables at runtime: @Test public void test() { MapFunction<String, Integer> fn = str -> Integer.valueOf(str); Class<?>[] typeArgs = TypeResolver.resolveRawArguments(MapFunction.class, fn.getClass()); for (Class<?> clazz : typeArgs) { System.out.println(clazz); } } outputs class java.lang.String class java.lang.Integer
|