# HG changeset patch # User Jaroslav Tulach # Date 1357657285 -3600 # Node ID c0bbf144c2c6e8c6fc8939bf3403fa164ee5c1fe # Parent b2464b3fd0153f2325e148e3281a286406e01396 Can invoke methods with parameters via reflection diff -r b2464b3fd015 -r c0bbf144c2c6 emul/src/main/java/java/lang/reflect/Method.java --- a/emul/src/main/java/java/lang/reflect/Method.java Mon Jan 07 18:40:20 2013 +0100 +++ b/emul/src/main/java/java/lang/reflect/Method.java Tue Jan 08 16:01:25 2013 +0100 @@ -26,6 +26,7 @@ package java.lang.reflect; import java.lang.annotation.Annotation; +import java.util.Enumeration; import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.emul.AnnotationImpl; import org.apidesign.bck2brwsr.emul.MethodImpl; @@ -140,24 +141,7 @@ * @return the return type for the method this object represents */ public Class getReturnType() { - switch (sig.charAt(0)) { - case 'I': return Integer.TYPE; - case 'J': return Long.TYPE; - case 'D': return Double.TYPE; - case 'F': return Float.TYPE; - case 'B': return Byte.TYPE; - case 'Z': return Boolean.TYPE; - case 'S': return Short.TYPE; - case 'V': return Void.TYPE; - case 'L': try { - int up = sig.indexOf("_2"); - String type = sig.substring(1, up); - return Class.forName(type); - } catch (ClassNotFoundException ex) { - // should not happen - } - } - throw new UnsupportedOperationException(sig); + return MethodImpl.signatureParser(sig).nextElement(); } /** @@ -199,8 +183,13 @@ * represents */ public Class[] getParameterTypes() { - throw new UnsupportedOperationException(); - //return (Class[]) parameterTypes.clone(); + Class[] arr = new Class[MethodImpl.signatureElements(sig) - 1]; + Enumeration en = MethodImpl.signatureParser(sig); + en.nextElement(); // return type + for (int i = 0; i < arr.length; i++) { + arr[i] = en.nextElement(); + } + return arr; } /** @@ -512,21 +501,41 @@ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - if ((getModifiers() & Modifier.STATIC) == 0 && obj == null) { + final boolean isStatic = (getModifiers() & Modifier.STATIC) == 0; + if (isStatic && obj == null) { throw new NullPointerException(); } - Object res = invoke0(this, obj, args); + Class[] types = getParameterTypes(); + if (types.length != args.length) { + throw new IllegalArgumentException("Types len " + types.length + " args: " + args.length); + } else { + args = args.clone(); + for (int i = 0; i < types.length; i++) { + Class c = types[i]; + if (c.isPrimitive()) { + args[i] = toPrimitive(c, args[i]); + } + } + } + Object res = invoke0(isStatic, this, obj, args); if (getReturnType().isPrimitive()) { res = fromPrimitive(getReturnType(), res); } return res; } - @JavaScriptBody(args = { "method", "self", "args" }, body = - "if (args.length > 0) throw 'unsupported now';" - + "return method.fld_data(self);" + @JavaScriptBody(args = { "st", "method", "self", "args" }, body = + "var p;\n" + + "if (st) {\n" + + " p = new Array(1);\n" + + " p[0] = self;\n" + + " p = p.concat(args);\n" + + "} else {\n" + + " p = args;\n" + + "}\n" + + "return method.fld_data.apply(self, p);\n" ) - private static native Object invoke0(Method m, Object self, Object[] args); + private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args); private static Object fromPrimitive(Class type, Object o) { if (type == Integer.TYPE) { @@ -560,6 +569,39 @@ body = "return cls.cnstr(false)[m](o);" ) private static native Integer fromRaw(Class cls, String m, Object o); + + private static Object toPrimitive(Class type, Object o) { + if (type == Integer.TYPE) { + return toRaw("intValue__I", o); + } + if (type == Long.TYPE) { + return toRaw("longValue__J", o); + } + if (type == Double.TYPE) { + return toRaw("doubleValue__D", o); + } + if (type == Float.TYPE) { + return toRaw("floatValue__F", o); + } + if (type == Byte.TYPE) { + return toRaw("byteValue__B", o); + } + if (type == Boolean.TYPE) { + return toRaw("booleanValue__Z", o); + } + if (type == Short.TYPE) { + return toRaw("shortValue__S", o); + } + if (type.getName().equals("void")) { + return o; + } + throw new IllegalStateException("Can't convert " + o); + } + + @JavaScriptBody(args = { "m", "o" }, + body = "return o[m](o);" + ) + private static native Object toRaw(String m, Object o); /** * Returns {@code true} if this method is a bridge diff -r b2464b3fd015 -r c0bbf144c2c6 emul/src/main/java/org/apidesign/bck2brwsr/emul/MethodImpl.java --- a/emul/src/main/java/org/apidesign/bck2brwsr/emul/MethodImpl.java Mon Jan 07 18:40:20 2013 +0100 +++ b/emul/src/main/java/org/apidesign/bck2brwsr/emul/MethodImpl.java Tue Jan 08 16:01:25 2013 +0100 @@ -25,6 +25,7 @@ package org.apidesign.bck2brwsr.emul; import java.lang.reflect.Method; +import java.util.Enumeration; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** Utilities to work on methods. @@ -96,5 +97,56 @@ } return arr; } + + public static int signatureElements(String sig) { + Enumeration en = signatureParser(sig); + int cnt = 0; + while (en.hasMoreElements()) { + en.nextElement(); + cnt++; + } + return cnt; + } + public static Enumeration signatureParser(final String sig) { + class E implements Enumeration { + int pos; + + public boolean hasMoreElements() { + return pos < sig.length(); + } + + public Class nextElement() { + switch (sig.charAt(pos++)) { + case 'I': + return Integer.TYPE; + case 'J': + return Long.TYPE; + case 'D': + return Double.TYPE; + case 'F': + return Float.TYPE; + case 'B': + return Byte.TYPE; + case 'Z': + return Boolean.TYPE; + case 'S': + return Short.TYPE; + case 'V': + return Void.TYPE; + case 'L': + try { + int up = sig.indexOf("_2"); + String type = sig.substring(1, up); + pos = up + 2; + return Class.forName(type); + } catch (ClassNotFoundException ex) { + // should not happen + } + } + throw new UnsupportedOperationException(sig + " at " + pos); + } + } + return new E(); + } } diff -r b2464b3fd015 -r c0bbf144c2c6 vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Mon Jan 07 18:40:20 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Tue Jan 08 16:01:25 2013 +0100 @@ -102,6 +102,11 @@ "java.io.IOException", true, "name" ); } + @Test public void jsInvokeParamMethod() throws Exception { + assertExec("sums two numbers via reflection", Classes.class, + "reflectiveSum__III", Double.valueOf(5), 2, 3 + ); + } @Test public void javaFindMethod() throws Exception { assertEquals(Classes.reflectiveMethodCall(false, "name"), "java.io.IOException", "Calls the name() method via reflection"); } diff -r b2464b3fd015 -r c0bbf144c2c6 vm/src/test/java/org/apidesign/vm4brwsr/Classes.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Mon Jan 07 18:40:20 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Tue Jan 08 16:01:25 2013 +0100 @@ -146,4 +146,9 @@ } return find.invoke(null); } + + public static int reflectiveSum(int a, int b) throws Exception { + Method m = StaticMethod.class.getMethod("sum", int.class, int.class); + return (int) m.invoke(null, a, b); + } } diff -r b2464b3fd015 -r c0bbf144c2c6 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Mon Jan 07 18:40:20 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Tue Jan 08 16:01:25 2013 +0100 @@ -77,6 +77,16 @@ } } + @Compare public String paramTypes() throws Exception { + Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE); + final Class[] pt = plus.getParameterTypes(); + return pt[0].getName(); + } + @Compare public int methodWithArgs() throws Exception { + Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE); + return (Integer)plus.invoke(null, 2, 3); + } + @JavaScriptBody(args = { "arr", "len" }, body="var a = arr.slice(0, len); a.sort(); return a;") private static String[] sort(String[] arr, int len) { List list = Arrays.asList(arr).subList(0, len); diff -r b2464b3fd015 -r c0bbf144c2c6 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Mon Jan 07 18:40:20 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Tue Jan 08 16:01:25 2013 +0100 @@ -24,4 +24,8 @@ public void instanceMethod() { } + + public static int plus(int a, int b) { + return a + b; + } }