Implementation of Class.getMethods reflection
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 05 Dec 2012 09:28:31 +0100
branchreflection
changeset 264ed0c92c81ea4
parent 262 683719ffcfe7
child 265 20c55abd6748
Implementation of Class.getMethods
emul/src/main/java/java/lang/Class.java
emul/src/main/java/java/lang/String.java
emul/src/main/java/java/lang/reflect/Method.java
vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java
vm/src/test/java/org/apidesign/vm4brwsr/Classes.java
     1.1 --- a/emul/src/main/java/java/lang/Class.java	Tue Dec 04 15:32:18 2012 +0100
     1.2 +++ b/emul/src/main/java/java/lang/Class.java	Wed Dec 05 09:28:31 2012 +0100
     1.3 @@ -616,7 +616,7 @@
     1.4       * @since JDK1.1
     1.5       */
     1.6      public Method[] getMethods() throws SecurityException {
     1.7 -        throw new SecurityException();
     1.8 +        return Method.findMethods(this);
     1.9      }
    1.10  
    1.11      /**
     2.1 --- a/emul/src/main/java/java/lang/String.java	Tue Dec 04 15:32:18 2012 +0100
     2.2 +++ b/emul/src/main/java/java/lang/String.java	Wed Dec 05 09:28:31 2012 +0100
     2.3 @@ -1767,7 +1767,7 @@
     2.4       *          or {@code -1} if there is no such occurrence.
     2.5       */
     2.6      @JavaScriptBody(args = { "self", "str", "fromIndex" }, body =
     2.7 -        "return self.toString().indexOf(str.toString(), fromIndex) >= 0;"
     2.8 +        "return self.toString().indexOf(str.toString(), fromIndex);"
     2.9      )
    2.10      public int indexOf(String str, int fromIndex) {
    2.11          return indexOf(toCharArray(), offset(), length(), str.toCharArray(), str.offset(), str.length(), fromIndex);
     3.1 --- a/emul/src/main/java/java/lang/reflect/Method.java	Tue Dec 04 15:32:18 2012 +0100
     3.2 +++ b/emul/src/main/java/java/lang/reflect/Method.java	Wed Dec 05 09:28:31 2012 +0100
     3.3 @@ -54,6 +54,7 @@
     3.4      private final Class<?> clazz;
     3.5      private final String name;
     3.6      private final Object data;
     3.7 +    private final String sig;
     3.8      private int modifiers;
     3.9  
    3.10     // Generics infrastructure
    3.11 @@ -65,12 +66,12 @@
    3.12       * instantiation of these objects in Java code from the java.lang
    3.13       * package via sun.reflect.LangReflectAccess.
    3.14       */
    3.15 -    Method(Class<?> declaringClass,
    3.16 -           String name, Object data)
    3.17 +    Method(Class<?> declaringClass, String name, Object data, String sig)
    3.18      {
    3.19          this.clazz = declaringClass;
    3.20          this.name = name;
    3.21          this.data = data;
    3.22 +        this.sig = sig;
    3.23      }
    3.24  
    3.25      /**
    3.26 @@ -594,29 +595,52 @@
    3.27      // bck2brwsr implementation
    3.28      //
    3.29  
    3.30 -    @JavaScriptBody(args = { "clazz", "name", "params" },
    3.31 -        body = "if (params.length > 0) return null;\n"
    3.32 +    @JavaScriptBody(args = { "clazz", "prefix" },
    3.33 +        body = ""
    3.34          + "var c = clazz.cnstr.prototype;"
    3.35 -        + "var prefix = name + '__';\n"
    3.36 +        + "var arr = new Array();\n"
    3.37          + "for (m in c) {\n"
    3.38 -        + "  if (m.indexOf(prefix) === 0) {"
    3.39 -        + "     return c[m];\n"
    3.40 +        + "  if (m.indexOf(prefix) === 0) {\n"
    3.41 +        + "     arr.push(m);\n"
    3.42 +        + "     arr.push(c[m]);\n"
    3.43          + "  }"
    3.44          + "}\n"
    3.45 -        + "return null;"
    3.46 +        + "return arr;"
    3.47      )
    3.48 -    private static native Object findMethodData(
    3.49 -        Class<?> clazz, String name, Class<?>... parameterTypes
    3.50 +    private static native Object[] findMethodData(
    3.51 +        Class<?> clazz, String prefix
    3.52      );
    3.53 -    
    3.54 +
    3.55      // XXX should not be public
    3.56      public static Method findMethod(
    3.57          Class<?> clazz, String name, Class<?>... parameterTypes
    3.58      ) {
    3.59 -        Object data = findMethodData(clazz, name, parameterTypes);
    3.60 -        if (data == null) {
    3.61 +        Object[] data = findMethodData(clazz, name + "__");
    3.62 +        if (data.length == 0) {
    3.63              return null;
    3.64          }
    3.65 -        return new Method(clazz, name, data);
    3.66 +        String sig = ((String)data[0]).substring(name.length() + 2);
    3.67 +        return new Method(clazz, name, data[1], sig);
    3.68 +    }
    3.69 +    
    3.70 +    public static Method[] findMethods(Class<?> clazz) {
    3.71 +        Object[] namesAndData = findMethodData(clazz, "");
    3.72 +        int cnt = 0;
    3.73 +        for (int i = 0; i < namesAndData.length; i += 2) {
    3.74 +            String sig = (String) namesAndData[i];
    3.75 +            Object data = namesAndData[i + 1];
    3.76 +            int middle = sig.indexOf("__");
    3.77 +            if (middle == -1) {
    3.78 +                continue;
    3.79 +            }
    3.80 +            String name = sig.substring(0, middle);
    3.81 +            sig = sig.substring(middle + 2);
    3.82 +            namesAndData[cnt++] = new Method(clazz, name, data, sig);
    3.83 +        }
    3.84 +        Method[] arr = new Method[cnt];
    3.85 +        for (int i = 0; i < cnt; i++) {
    3.86 +            arr[i] = (Method)namesAndData[i];
    3.87 +        }
    3.88 +        return arr;
    3.89      }
    3.90  }
     4.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Tue Dec 04 15:32:18 2012 +0100
     4.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Wed Dec 05 09:28:31 2012 +0100
     4.3 @@ -89,7 +89,16 @@
     4.4      @Test public void jsInvokeMethod() throws Exception {
     4.5          assertExec("Calls the name() method via reflection", Classes.class, 
     4.6              "reflectiveMethodCall__Ljava_lang_Object_2Z", 
     4.7 -            "java.io.IOException"
     4.8 +            "java.io.IOException", true
     4.9 +        );
    4.10 +    }
    4.11 +    @Test public void javaFindMethod() throws Exception {
    4.12 +        assertEquals(Classes.reflectiveMethodCall(false), "java.io.IOException", "Calls the name() method via reflection");
    4.13 +    }
    4.14 +    @Test public void jsFindMethod() throws Exception {
    4.15 +        assertExec("Calls the name() method via reflection", Classes.class, 
    4.16 +            "reflectiveMethodCall__Ljava_lang_Object_2Z", 
    4.17 +            "java.io.IOException", false
    4.18          );
    4.19      }
    4.20      
     5.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java	Tue Dec 04 15:32:18 2012 +0100
     5.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java	Wed Dec 05 09:28:31 2012 +0100
     5.3 @@ -21,6 +21,7 @@
     5.4  import java.lang.annotation.Annotation;
     5.5  import java.lang.reflect.Method;
     5.6  import java.net.MalformedURLException;
     5.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
     5.8  
     5.9  /**
    5.10   *
    5.11 @@ -79,20 +80,32 @@
    5.12          return null;
    5.13      }
    5.14      
    5.15 +    @JavaScriptBody(args = "msg", body = "throw msg;")
    5.16 +    private static native void thrw(String msg);
    5.17 +    
    5.18      public static Object reflectiveMethodCall(boolean direct) throws Exception {
    5.19 -        Method m;
    5.20 -        /*
    5.21 +        Method find = null;
    5.22 +        StringBuilder sb = new StringBuilder();
    5.23          if (!direct) {
    5.24              final Class<? extends Annotation> v = ClassesMarker.class;
    5.25 -            for (Method single : Classes.class.getMethods()) {
    5.26 -                if (single.getAnnotation(v)) {
    5.27 -                    m = single;
    5.28 +            for (Method m : Classes.class.getMethods()) {
    5.29 +                sb.append("\n").append(m.getName());
    5.30 +                if (m.getName().equals("name")) {
    5.31 +                    find = m;
    5.32                      break;
    5.33                  }
    5.34 +//                if (single.getAnnotation(v) != null) {
    5.35 +//                    m = single;
    5.36 +//                    break;
    5.37 +//                }
    5.38              }
    5.39 -        } else*/ {
    5.40 -            m = Classes.class.getMethod("name");
    5.41 +        } else {
    5.42 +            find = Classes.class.getMethod("name");
    5.43          }
    5.44 -        return m.invoke(null);
    5.45 +        if (find == null) {
    5.46 +            thrw(sb.toString());
    5.47 +            throw new NullPointerException(sb.toString());
    5.48 +        }
    5.49 +        return find.invoke(null);
    5.50      }
    5.51  }