|
|
@@ -7,14 +7,12 @@
|
|
|
|
|
|
package net.ranides.assira.reflection;
|
|
|
|
|
|
+import java.lang.reflect.Array;
|
|
|
import java.lang.reflect.Method;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.List;
|
|
|
-import java.util.function.BiFunction;
|
|
|
+import java.lang.reflect.ParameterizedType;
|
|
|
import java.util.function.Function;
|
|
|
-import java.util.stream.Collectors;
|
|
|
import net.ranides.asm.Type;
|
|
|
-import net.ranides.assira.text.StringUtils;
|
|
|
+import net.ranides.assira.trace.ExceptionUtils;
|
|
|
import sun.reflect.ConstantPool;
|
|
|
|
|
|
/**
|
|
|
@@ -40,27 +38,46 @@ public class LambdaParams {
|
|
|
System.out.printf("(Params2 a) -> Integer %n");
|
|
|
that.runme( (Param2 v) -> 3*OtherLambda.flow("s") );
|
|
|
System.out.printf("%n%n");
|
|
|
-
|
|
|
- System.out.printf("(Param2, Float) -> Integer %n");
|
|
|
- that.runme( (Param2 v, Float z) -> z * OtherLambda.flow("s") );
|
|
|
+
|
|
|
+ System.out.printf("(String) -> Integer %n");
|
|
|
+ that.runme( new Function<String, Integer>() {
|
|
|
+ @Override
|
|
|
+ public Integer apply(String t) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+ System.out.printf("%n%n");
|
|
|
+
|
|
|
+ System.out.printf("(Float) -> Double %n");
|
|
|
+ that.runme( new Hello(22));
|
|
|
+ System.out.printf("%n%n");
|
|
|
+
|
|
|
+ Function<Integer, ?> f31 = (Integer a) -> "A";
|
|
|
+ Function f32 = f31;
|
|
|
+
|
|
|
+ System.out.printf("(Integer) -> String %n");
|
|
|
+ that.runme(f32);
|
|
|
System.out.printf("%n%n");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
public <T,R> void runme(Function<T,R> function) throws Exception {
|
|
|
- dump(function);
|
|
|
+ System.out.printf("type = %s%n", typeof(function));
|
|
|
}
|
|
|
|
|
|
- public <T,U,R> void runme(BiFunction<T,U,R> function) throws Exception {
|
|
|
- dump(function);
|
|
|
+ public static Class<?> typeof(Function function) throws Exception {
|
|
|
+// if(!function.getClass().isSynthetic()) {
|
|
|
+// return typeof_generic(function);
|
|
|
+// } else {
|
|
|
+ return typeof_lambda(function);
|
|
|
+// }
|
|
|
}
|
|
|
|
|
|
- private static void dump(Object function) throws Exception {
|
|
|
- Method GET_CONSTANT_POOL = Class.class.getDeclaredMethod("getConstantPool");
|
|
|
- GET_CONSTANT_POOL.setAccessible(true);
|
|
|
- ConstantPool cp = (ConstantPool) GET_CONSTANT_POOL.invoke(function.getClass());
|
|
|
+ private static Class<?> typeof_lambda(Function function) {
|
|
|
+ ConstantPool cp = Li.get(function.getClass());
|
|
|
|
|
|
for(int i=0; i<cp.getSize(); i++) {
|
|
|
- String[] info = null;
|
|
|
+ String[] info;
|
|
|
try {
|
|
|
info = cp.getMemberRefInfoAt(i);
|
|
|
} catch(Exception ex) {
|
|
|
@@ -68,39 +85,108 @@ public class LambdaParams {
|
|
|
}
|
|
|
|
|
|
String parent = info[0];
|
|
|
-
|
|
|
if("java/lang/Object".equals(parent) || "java/lang/Class".equals(parent)) {
|
|
|
continue;
|
|
|
}
|
|
|
- if(parent.startsWith("com/zeroturnaround/")) {
|
|
|
- continue;
|
|
|
- }
|
|
|
try {
|
|
|
- String name = info[1];
|
|
|
- Type type = Type.getReturnType(info[2]);
|
|
|
- List<Type> tparams = Arrays.asList(Type.getArgumentTypes(info[2]));
|
|
|
- List<String> sparams = tparams.stream().map(Type::getClassName).collect(Collectors.toList());
|
|
|
-
|
|
|
- System.out.printf("[%d] (%s) -> %s @ %s # %s%n",
|
|
|
- i,
|
|
|
- StringUtils.join(sparams, ", "),
|
|
|
- type.getClassName(),
|
|
|
- parent, name
|
|
|
- );
|
|
|
+ if(1 != Type.getArgumentTypes(info[2]).length) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
} catch(Exception ex) {
|
|
|
- System.out.printf("[%d] ERROR = %s # %s : %s%n", i, info[0], info[1], ex);
|
|
|
+ continue;
|
|
|
}
|
|
|
-// break;
|
|
|
|
|
|
+ return vm2class(function.getClass().getClassLoader(), Type.getReturnType(info[2]).getDescriptor());
|
|
|
+ }
|
|
|
+ throw new AssertionError("Deduction of return type failed. Unsupported lambda: " + function);
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("PMD")
|
|
|
+ private static Class<?> vm2class(ClassLoader loader, String vmtype) {
|
|
|
+ try {
|
|
|
+ if(vmtype.startsWith("[")) {
|
|
|
+ return Array.newInstance(vm2class(loader, vmtype.substring(1)), 0).getClass();
|
|
|
+ }
|
|
|
+ if(vmtype.startsWith("L") && vmtype.endsWith(";")) {
|
|
|
+ return Class.forName(vmtype.substring(1,vmtype.length()-1).replace('/', '.'), false, loader);
|
|
|
+ }
|
|
|
+ if("Z".equals(vmtype)) {
|
|
|
+ return boolean.class;
|
|
|
+ }
|
|
|
+ if("B".equals(vmtype)) {
|
|
|
+ return byte.class;
|
|
|
+ }
|
|
|
+ if("C".equals(vmtype)) {
|
|
|
+ return char.class;
|
|
|
+ }
|
|
|
+ if("S".equals(vmtype)) {
|
|
|
+ return short.class;
|
|
|
+ }
|
|
|
+ if("I".equals(vmtype)) {
|
|
|
+ return int.class;
|
|
|
+ }
|
|
|
+ if("J".equals(vmtype)) {
|
|
|
+ return long.class;
|
|
|
+ }
|
|
|
+ if("F".equals(vmtype)) {
|
|
|
+ return float.class;
|
|
|
+ }
|
|
|
+ if("D".equals(vmtype)) {
|
|
|
+ return double.class;
|
|
|
+ }
|
|
|
+ if("V".equals(vmtype)) {
|
|
|
+ return void.class;
|
|
|
+ }
|
|
|
+ } catch(ClassNotFoundException cause) {
|
|
|
+ throw ExceptionUtils.rethrow(cause);
|
|
|
+ }
|
|
|
+ throw new AssertionError("Unknown type: " + vmtype);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Class<?> typeof_generic(Object function) {
|
|
|
+ ParameterizedType it = getGenericInterface(function.getClass(), Function.class);
|
|
|
+ java.lang.reflect.Type pt = it.getActualTypeArguments()[1];
|
|
|
+ if(pt instanceof Class<?>) {
|
|
|
+ return (Class<?>)pt;
|
|
|
+ }
|
|
|
+ if(pt instanceof ParameterizedType) {
|
|
|
+ return (Class<?>)(((ParameterizedType)pt).getRawType());
|
|
|
+ }
|
|
|
+ throw new AssertionError("Deduction of return type failed. Unsupported function: " + function);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static ParameterizedType getGenericInterface(Class<?> type, Class<?> intface) {
|
|
|
+ for(java.lang.reflect.Type t : type.getGenericInterfaces()) {
|
|
|
+ ParameterizedType pt = (ParameterizedType)t;
|
|
|
+ if( intface.equals(pt.getRawType()) ) {
|
|
|
+ return pt;
|
|
|
+ }
|
|
|
}
|
|
|
+ throw new AssertionError(type.getName() + " does not implement " + intface.getName());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static final class Li { // NOPMD - lazy init idiom
|
|
|
|
|
|
-// System.out.printf("%s%n", Arrays.asList(constantPool.getMemberRefInfoAt(2)));
|
|
|
+ public static final Method GET_CONSTANT_POOL;
|
|
|
+
|
|
|
+ static {
|
|
|
+ try {
|
|
|
+ GET_CONSTANT_POOL = Class.class.getDeclaredMethod("getConstantPool");
|
|
|
+ GET_CONSTANT_POOL.setAccessible(true);
|
|
|
+ } catch(ReflectiveOperationException cause) {
|
|
|
+ throw ExceptionUtils.rethrow(cause);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static ConstantPool get(Class<?> type) {
|
|
|
+ try {
|
|
|
+ return (ConstantPool) GET_CONSTANT_POOL.invoke(type);
|
|
|
+ } catch (ReflectiveOperationException cause) {
|
|
|
+ throw ExceptionUtils.rethrow(cause);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-// String[] methodRefInfo = constantPool.getMemberRefInfoAt(constantPool.getSize() - 2);
|
|
|
-//
|
|
|
-// int argumentIndex = 0;
|
|
|
-// String argumentType = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodRefInfo[2])[argumentIndex].getClassName();
|
|
|
-// Class<?> type = (Class<?>) Class.forName(argumentType);
|
|
|
}
|
|
|
|
|
|
}
|