Переглянути джерело

lambda parameters: using ConstantPool

Ranides Atterwim 10 роки тому
батько
коміт
c476465d5e

+ 33 - 0
assira.drafts/src/main/java/net/ranides/assira/reflection/Hello.java

@@ -0,0 +1,33 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira.drafts
+ */
+
+package net.ranides.assira.reflection;
+
+import java.util.function.Function;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+final class Hello implements Function<Float, Double> {
+
+	private final double i;
+
+	public Hello(double i) {
+		this.i = i;
+	}
+
+	@Override
+	public Double apply(Float t) {
+		return i * t;
+	}
+
+	public double getI() {
+		return i;
+	}
+
+}

+ 126 - 40
assira.drafts/src/main/java/net/ranides/assira/reflection/LambdaParams.java

@@ -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);
 	}
 	
 }