Can obtain annotation from a method reflection
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 05 Dec 2012 10:03:58 +0100
branchreflection
changeset 2662e2e6f946208
parent 265 20c55abd6748
child 267 79697fa91bfc
child 648 77735e75d6dc
Can obtain annotation from a method
emul/src/main/java/java/lang/AnnotationImpl.java
emul/src/main/java/java/lang/Class.java
emul/src/main/java/java/lang/reflect/Method.java
emul/src/main/java/org/apidesign/bck2brwsr/emul/AnnotationImpl.java
vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java
     1.1 --- a/emul/src/main/java/java/lang/AnnotationImpl.java	Wed Dec 05 09:31:36 2012 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,68 +0,0 @@
     1.4 -/*
     1.5 - * To change this template, choose Tools | Templates
     1.6 - * and open the template in the editor.
     1.7 - */
     1.8 -package java.lang;
     1.9 -
    1.10 -import java.lang.annotation.Annotation;
    1.11 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.12 -
    1.13 -/**
    1.14 - *
    1.15 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    1.16 - */
    1.17 -final class AnnotationImpl implements Annotation {
    1.18 -    public Class<? extends Annotation> annotationType() {
    1.19 -        return getClass();
    1.20 -    }
    1.21 -
    1.22 -    @JavaScriptBody(args = { "a", "n", "values" }, body = ""
    1.23 -        + "function f(v, p) {\n"
    1.24 -        + "  var val = v;\n"
    1.25 -        + "  var prop = p;\n"
    1.26 -        + "  return function() {\n"
    1.27 -        + "    return val[prop];\n"
    1.28 -        + "  };\n"
    1.29 -        + "}\n"
    1.30 -        + "var props = Object.getOwnPropertyNames(values);\n"
    1.31 -        + "for (var i = 0; i < props.length; i++) {\n"
    1.32 -        + "  var p = props[i];\n"
    1.33 -        + "  a[p] = new f(values, p);\n"
    1.34 -        + "}\n"
    1.35 -        + "a['$instOf_' + n] = true;\n"
    1.36 -        + "return a;"
    1.37 -    )
    1.38 -    private static <T extends Annotation> T create(AnnotationImpl a, String n, Object values) {
    1.39 -        return null;
    1.40 -    }
    1.41 -    static <T extends Annotation> T create(Class<T> annoClass, Object values) {
    1.42 -        return create(new AnnotationImpl(), annoClass.getName().replace('.', '_'), values);
    1.43 -    }
    1.44 -
    1.45 -    static Annotation[] create(Object anno) {
    1.46 -        String[] names = findNames(anno);
    1.47 -        Annotation[] ret = new Annotation[names.length];
    1.48 -        for (int i = 0; i < names.length; i++) {
    1.49 -            String n = names[i].substring(1, names[i].length() - 1).replace('/', '_');
    1.50 -            ret[i] = create(new AnnotationImpl(), n, findData(anno, names[i]));
    1.51 -        }
    1.52 -        return ret;
    1.53 -    }
    1.54 -    @JavaScriptBody(args = "anno", body =
    1.55 -          "var arr = new Array();"
    1.56 -        + "var props = Object.getOwnPropertyNames(anno);\n"
    1.57 -        + "for (var i = 0; i < props.length; i++) {\n"
    1.58 -        + "  var p = props[i];\n"
    1.59 -        + "  arr.push(p);"
    1.60 -        + "}"
    1.61 -        + "return arr;"
    1.62 -    )
    1.63 -    private static String[] findNames(Object anno) {
    1.64 -        throw new UnsupportedOperationException();
    1.65 -    }
    1.66 -
    1.67 -    @JavaScriptBody(args={ "anno", "p"}, body="return anno[p];")
    1.68 -    private static Object findData(Object anno, String p) {
    1.69 -        throw new UnsupportedOperationException();
    1.70 -    }
    1.71 -}
     2.1 --- a/emul/src/main/java/java/lang/Class.java	Wed Dec 05 09:31:36 2012 +0100
     2.2 +++ b/emul/src/main/java/java/lang/Class.java	Wed Dec 05 10:03:58 2012 +0100
     2.3 @@ -25,6 +25,7 @@
     2.4  
     2.5  package java.lang;
     2.6  
     2.7 +import org.apidesign.bck2brwsr.emul.AnnotationImpl;
     2.8  import java.io.InputStream;
     2.9  import java.lang.annotation.Annotation;
    2.10  import java.lang.reflect.Field;
    2.11 @@ -1025,7 +1026,7 @@
    2.12          body = 
    2.13            "if (self.anno) {"
    2.14          + "  return self.anno['L' + ac.jvmName + ';'];"
    2.15 -        + "}"
    2.16 +        + "} else return null;"
    2.17      )
    2.18      private Object getAnnotationData(Class<?> annotationClass) {
    2.19          throw new UnsupportedOperationException();
     3.1 --- a/emul/src/main/java/java/lang/reflect/Method.java	Wed Dec 05 09:31:36 2012 +0100
     3.2 +++ b/emul/src/main/java/java/lang/reflect/Method.java	Wed Dec 05 10:03:58 2012 +0100
     3.3 @@ -27,6 +27,7 @@
     3.4  
     3.5  import java.lang.annotation.Annotation;
     3.6  import org.apidesign.bck2brwsr.core.JavaScriptBody;
     3.7 +import org.apidesign.bck2brwsr.emul.AnnotationImpl;
     3.8  
     3.9  /**
    3.10   * A {@code Method} provides information about, and access to, a single method
    3.11 @@ -535,15 +536,23 @@
    3.12          return Modifier.isSynthetic(getModifiers());
    3.13      }
    3.14  
    3.15 +    @JavaScriptBody(args = { "self", "ac" }, 
    3.16 +        body = 
    3.17 +          "if (self.fld_data.anno) {"
    3.18 +        + "  return self.fld_data.anno['L' + ac.jvmName + ';'];"
    3.19 +        + "} else return null;"
    3.20 +    )
    3.21 +    private Object getAnnotationData(Class<?> annotationClass) {
    3.22 +        throw new UnsupportedOperationException();
    3.23 +    }
    3.24 +    
    3.25      /**
    3.26       * @throws NullPointerException {@inheritDoc}
    3.27       * @since 1.5
    3.28       */
    3.29      public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
    3.30 -        if (annotationClass == null)
    3.31 -            throw new NullPointerException();
    3.32 -
    3.33 -        throw new UnsupportedOperationException();
    3.34 +        Object data = getAnnotationData(annotationClass);
    3.35 +        return data == null ? null : AnnotationImpl.create(annotationClass, data);
    3.36      }
    3.37  
    3.38      /**
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/emul/src/main/java/org/apidesign/bck2brwsr/emul/AnnotationImpl.java	Wed Dec 05 10:03:58 2012 +0100
     4.3 @@ -0,0 +1,68 @@
     4.4 +/*
     4.5 + * To change this template, choose Tools | Templates
     4.6 + * and open the template in the editor.
     4.7 + */
     4.8 +package org.apidesign.bck2brwsr.emul;
     4.9 +
    4.10 +import java.lang.annotation.Annotation;
    4.11 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    4.12 +
    4.13 +/**
    4.14 + *
    4.15 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    4.16 + */
    4.17 +public final class AnnotationImpl implements Annotation {
    4.18 +    public Class<? extends Annotation> annotationType() {
    4.19 +        return getClass();
    4.20 +    }
    4.21 +
    4.22 +    @JavaScriptBody(args = { "a", "n", "values" }, body = ""
    4.23 +        + "function f(v, p) {\n"
    4.24 +        + "  var val = v;\n"
    4.25 +        + "  var prop = p;\n"
    4.26 +        + "  return function() {\n"
    4.27 +        + "    return val[prop];\n"
    4.28 +        + "  };\n"
    4.29 +        + "}\n"
    4.30 +        + "var props = Object.getOwnPropertyNames(values);\n"
    4.31 +        + "for (var i = 0; i < props.length; i++) {\n"
    4.32 +        + "  var p = props[i];\n"
    4.33 +        + "  a[p] = new f(values, p);\n"
    4.34 +        + "}\n"
    4.35 +        + "a['$instOf_' + n] = true;\n"
    4.36 +        + "return a;"
    4.37 +    )
    4.38 +    private static <T extends Annotation> T create(AnnotationImpl a, String n, Object values) {
    4.39 +        return null;
    4.40 +    }
    4.41 +    public static <T extends Annotation> T create(Class<T> annoClass, Object values) {
    4.42 +        return create(new AnnotationImpl(), annoClass.getName().replace('.', '_'), values);
    4.43 +    }
    4.44 +
    4.45 +    public static Annotation[] create(Object anno) {
    4.46 +        String[] names = findNames(anno);
    4.47 +        Annotation[] ret = new Annotation[names.length];
    4.48 +        for (int i = 0; i < names.length; i++) {
    4.49 +            String n = names[i].substring(1, names[i].length() - 1).replace('/', '_');
    4.50 +            ret[i] = create(new AnnotationImpl(), n, findData(anno, names[i]));
    4.51 +        }
    4.52 +        return ret;
    4.53 +    }
    4.54 +    @JavaScriptBody(args = "anno", body =
    4.55 +          "var arr = new Array();"
    4.56 +        + "var props = Object.getOwnPropertyNames(anno);\n"
    4.57 +        + "for (var i = 0; i < props.length; i++) {\n"
    4.58 +        + "  var p = props[i];\n"
    4.59 +        + "  arr.push(p);"
    4.60 +        + "}"
    4.61 +        + "return arr;"
    4.62 +    )
    4.63 +    private static String[] findNames(Object anno) {
    4.64 +        throw new UnsupportedOperationException();
    4.65 +    }
    4.66 +
    4.67 +    @JavaScriptBody(args={ "anno", "p"}, body="return anno[p];")
    4.68 +    private static Object findData(Object anno, String p) {
    4.69 +        throw new UnsupportedOperationException();
    4.70 +    }
    4.71 +}
     5.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Wed Dec 05 09:31:36 2012 +0100
     5.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Wed Dec 05 10:03:58 2012 +0100
     5.3 @@ -121,10 +121,17 @@
     5.4                  }
     5.5                  continue;
     5.6              }
     5.7 +            String mn;
     5.8              if (m.isStatic()) {
     5.9 -                generateStaticMethod("\n    c.", m, toInitilize);
    5.10 +                mn = generateStaticMethod("\n    c.", m, toInitilize);
    5.11              } else {
    5.12 -                generateInstanceMethod("\n    c.", m);
    5.13 +                mn = generateInstanceMethod("\n    c.", m);
    5.14 +            }
    5.15 +            byte[] runAnno = m.findAnnotationData(false);
    5.16 +            if (runAnno != null) {
    5.17 +                out.append("\n    c.").append(mn).append(".anno = {");
    5.18 +                generateAnno(jc, out, runAnno);
    5.19 +                out.append("\n    };");
    5.20              }
    5.21          }
    5.22          out.append("\n    c.constructor = CLS;");
    5.23 @@ -175,9 +182,10 @@
    5.24          }
    5.25          return sb.toString();
    5.26      }
    5.27 -    private void generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
    5.28 -        if (javaScriptBody(prefix, m, true)) {
    5.29 -            return;
    5.30 +    private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
    5.31 +        String jsb = javaScriptBody(prefix, m, true);
    5.32 +        if (jsb != null) {
    5.33 +            return jsb;
    5.34          }
    5.35          StringBuilder argsCnt = new StringBuilder();
    5.36          final String mn = findMethodName(m, argsCnt);
    5.37 @@ -212,11 +220,13 @@
    5.38              out.append("  throw 'no code found for ").append(m.getInternalSig()).append("';\n");
    5.39          }
    5.40          out.append("};");
    5.41 +        return mn;
    5.42      }
    5.43      
    5.44 -    private void generateInstanceMethod(String prefix, MethodData m) throws IOException {
    5.45 -        if (javaScriptBody(prefix, m, false)) {
    5.46 -            return;
    5.47 +    private String generateInstanceMethod(String prefix, MethodData m) throws IOException {
    5.48 +        String jsb = javaScriptBody(prefix, m, false);
    5.49 +        if (jsb != null) {
    5.50 +            return jsb;
    5.51          }
    5.52          StringBuilder argsCnt = new StringBuilder();
    5.53          final String mn = findMethodName(m, argsCnt);
    5.54 @@ -246,6 +256,7 @@
    5.55              out.append("  throw 'no code found for ").append(m.getInternalSig()).append("';\n");
    5.56          }
    5.57          out.append("};");
    5.58 +        return mn;
    5.59      }
    5.60  
    5.61      private void produceCode(byte[] byteCodes) throws IOException {
    5.62 @@ -1024,10 +1035,10 @@
    5.63          return s;
    5.64      }
    5.65  
    5.66 -    private boolean javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
    5.67 +    private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
    5.68          byte[] arr = m.findAnnotationData(true);
    5.69          if (arr == null) {
    5.70 -            return false;
    5.71 +            return null;
    5.72          }
    5.73          final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
    5.74          class P extends AnnotationParser {
    5.75 @@ -1055,10 +1066,11 @@
    5.76          P p = new P();
    5.77          p.parse(arr, jc);
    5.78          if (p.body == null) {
    5.79 -            return false;
    5.80 +            return null;
    5.81          }
    5.82          StringBuilder cnt = new StringBuilder();
    5.83 -        out.append(prefix).append(findMethodName(m, cnt));
    5.84 +        final String mn = findMethodName(m, cnt);
    5.85 +        out.append(prefix).append(mn);
    5.86          out.append(" = function(");
    5.87          String space;
    5.88          int index;
    5.89 @@ -1079,7 +1091,7 @@
    5.90          out.append(") {").append("\n");
    5.91          out.append(p.body);
    5.92          out.append("\n}\n");
    5.93 -        return true;
    5.94 +        return mn;
    5.95      }
    5.96      private static String className(ClassData jc) {
    5.97          //return jc.getName().getInternalName().replace('/', '_');
    5.98 @@ -1155,6 +1167,9 @@
    5.99              @Override
   5.100              protected void visitAttr(String type, String attr, String attrType, String value) 
   5.101              throws IOException {
   5.102 +                if (attr == null) {
   5.103 +                    return;
   5.104 +                }
   5.105                  if (cnt++ > 0) {
   5.106                      out.append(",\n");
   5.107                  }
     6.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Wed Dec 05 09:31:36 2012 +0100
     6.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Wed Dec 05 10:03:58 2012 +0100
     6.3 @@ -101,6 +101,15 @@
     6.4              "java.io.IOException", false, "name"
     6.5          );
     6.6      }
     6.7 +    @Test public void javaAnnotatedMethod() throws Exception {
     6.8 +        assertEquals(Classes.reflectiveMethodCall(false, null), "java.io.IOException", "Calls the name() method via reflection");
     6.9 +    }
    6.10 +    @Test public void jsAnnotatedMethod() throws Exception {
    6.11 +        assertExec("Calls the name() method via reflection", Classes.class, 
    6.12 +            "reflectiveMethodCall__Ljava_lang_Object_2ZLjava_lang_String_2", 
    6.13 +            "java.io.IOException", false, null
    6.14 +        );
    6.15 +    }
    6.16      
    6.17      private static CharSequence codeSeq;
    6.18      private static Invocable code;