package cucumber.runtime.java8; import cucumber.runtime.CucumberException; import cucumber.api.java8.StepdefBody; import cucumber.runtime.java.TypeIntrospector; import sun.reflect.ConstantPool; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; public class ConstantPoolTypeIntrospector implements TypeIntrospector { private static final Method Class_getConstantPool; static { try { Class_getConstantPool = Class.class.getDeclaredMethod("getConstantPool"); Class_getConstantPool.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); } } public static final TypeIntrospector INSTANCE = new ConstantPoolTypeIntrospector(); @Override public Type[] getGenericTypes(Class<? extends StepdefBody> clazz, Class<? extends StepdefBody> interfac3) throws Exception { ConstantPool constantPool = (ConstantPool) Class_getConstantPool.invoke(clazz); String typeString = getLambdaTypeString(constantPool); int typeParameterCount = interfac3.getTypeParameters().length; jdk.internal.org.objectweb.asm.Type[] argumentTypes = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(typeString); // Only look at the N last arguments to the lambda static method, since the first ones might be variables // who only pass in the states of closed variables List<jdk.internal.org.objectweb.asm.Type> interestingArgumentTypes = Arrays.asList(argumentTypes) .subList(argumentTypes.length - typeParameterCount, argumentTypes.length); Type[] typeArguments = new Type[typeParameterCount]; for (int i = 0; i < typeParameterCount; i++) { typeArguments[i] = Class.forName(interestingArgumentTypes.get(i).getClassName()); } return typeArguments; } private String getLambdaTypeString(ConstantPool constantPool) { int size = constantPool.getSize(); String[] memberRef = null; // find last element in constantPool with valid memberRef // - previously always at size-2 index but changed with JDK 1.8.0_60 for (int i = size - 1; i > -1; i--) { try { memberRef = constantPool.getMemberRefInfoAt(i); return memberRef[2]; } catch (IllegalArgumentException e) { // eat error; null entry at ConstantPool index? } } throw new CucumberException("Couldn't find memberRef."); } }