Initial support for runtime annotations reflection
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 02 Dec 2012 12:26:14 +0100
branchreflection
changeset 235bf0a77f029c4
parent 234 a2f1380f8a28
child 236 d97770281580
Initial support for runtime annotations
emul/src/main/java/java/lang/AnnotationImpl.java
emul/src/main/java/java/lang/Class.java
javap/src/main/java/org/apidesign/javap/AnnotationParser.java
vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java
vm/src/test/java/org/apidesign/vm4brwsr/Classes.java
vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/emul/src/main/java/java/lang/AnnotationImpl.java	Sun Dec 02 12:26:14 2012 +0100
     1.3 @@ -0,0 +1,33 @@
     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 +          "var v = values;"
    1.24 +        + "for (p in values) {"
    1.25 +        + "  a[p + 'I'] = function() { return v[p]; }"
    1.26 +        + "}"
    1.27 +        + "a['$instOf_' + n] = true;"
    1.28 +        + "return a;"
    1.29 +    )
    1.30 +    private static <T extends Annotation> T create(AnnotationImpl a, String n, Object values) {
    1.31 +        return null;
    1.32 +    }
    1.33 +    static <T extends Annotation> T create(Class<T> annoClass, Object values) {
    1.34 +        return create(new AnnotationImpl(), annoClass.getName().replace('.', '_'), values);
    1.35 +    }
    1.36 +}
     2.1 --- a/emul/src/main/java/java/lang/Class.java	Sun Dec 02 06:34:14 2012 +0100
     2.2 +++ b/emul/src/main/java/java/lang/Class.java	Sun Dec 02 12:26:14 2012 +0100
     2.3 @@ -774,14 +774,28 @@
     2.4       * @throws NullPointerException {@inheritDoc}
     2.5       * @since 1.5
     2.6       */
     2.7 +    @JavaScriptBody(args = { "self", "ac" }, 
     2.8 +        body = 
     2.9 +          "if (self.anno) {"
    2.10 +        + "  return self.anno['L' + ac.jvmName + ';'];"
    2.11 +        + "}"
    2.12 +    )
    2.13 +    private Object getAnnotationData(Class<?> annotationClass) {
    2.14 +        throw new UnsupportedOperationException();
    2.15 +    }
    2.16      public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
    2.17 -        throw new UnsupportedOperationException();
    2.18 +        Object data = getAnnotationData(annotationClass);
    2.19 +        return data == null ? null : AnnotationImpl.create(annotationClass, data);
    2.20      }
    2.21  
    2.22      /**
    2.23       * @throws NullPointerException {@inheritDoc}
    2.24       * @since 1.5
    2.25       */
    2.26 +    @JavaScriptBody(args = { "self", "ac" }, 
    2.27 +        body = "if (self.anno && self.anno['L' + ac.jvmName + ';']) { return true; }"
    2.28 +        + "else return false;"
    2.29 +    )
    2.30      public boolean isAnnotationPresent(
    2.31          Class<? extends Annotation> annotationClass) {
    2.32          if (annotationClass == null)
     3.1 --- a/javap/src/main/java/org/apidesign/javap/AnnotationParser.java	Sun Dec 02 06:34:14 2012 +0100
     3.2 +++ b/javap/src/main/java/org/apidesign/javap/AnnotationParser.java	Sun Dec 02 12:26:14 2012 +0100
     3.3 @@ -37,7 +37,15 @@
     3.4      protected AnnotationParser() {
     3.5      }
     3.6  
     3.7 -    protected void visitAttr(String type, String attr, String value) {
     3.8 +    protected void visitAnnotationStart(String type) throws IOException {
     3.9 +    }
    3.10 +
    3.11 +    protected void visitAnnotationEnd(String type) throws IOException {
    3.12 +    }
    3.13 +    
    3.14 +    protected void visitAttr(
    3.15 +        String type, String attr, String value
    3.16 +    ) throws IOException {
    3.17      }
    3.18      
    3.19      /** Initialize the parsing with constant pool from <code>cd</code>.
    3.20 @@ -66,11 +74,13 @@
    3.21      private void readAnno(DataInputStream dis, ClassData cd) throws IOException {
    3.22          int type = dis.readUnsignedShort();
    3.23          String typeName = cd.StringValue(type);
    3.24 +        visitAnnotationStart(typeName);
    3.25      	int cnt = dis.readUnsignedShort();
    3.26      	for (int i = 0; i < cnt; i++) {
    3.27              String attrName = cd.StringValue(dis.readUnsignedShort());
    3.28              readValue(dis, cd, typeName, attrName);
    3.29          }
    3.30 +        visitAnnotationEnd(typeName);
    3.31      }
    3.32  
    3.33      private void readValue(DataInputStream dis, ClassData cd, String typeName, String attrName) 
     4.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Sun Dec 02 06:34:14 2012 +0100
     4.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Sun Dec 02 12:26:14 2012 +0100
     4.3 @@ -119,6 +119,12 @@
     4.4          out.append("\n    CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
     4.5          out.append("\n    CLS.$class.superclass = sprcls;");
     4.6          out.append("\n    CLS.$class.cnstr = CLS;");
     4.7 +        byte[] classAnno = jc.findAnnotationData(false);
     4.8 +        if (classAnno != null) {
     4.9 +            out.append("\n    CLS.$class.anno = {");
    4.10 +            generateAnno(jc, out, classAnno);
    4.11 +            out.append("\n    };");
    4.12 +        }
    4.13          out.append("\n  }");
    4.14          out.append("\n  if (arguments.length === 0) {");
    4.15          out.append("\n    if (!(this instanceof CLS)) {");
    4.16 @@ -1085,4 +1091,31 @@
    4.17          }
    4.18          return " = null;";
    4.19      }
    4.20 +
    4.21 +    private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
    4.22 +        AnnotationParser ap = new AnnotationParser() {
    4.23 +            int cnt;
    4.24 +            
    4.25 +            @Override
    4.26 +            protected void visitAnnotationStart(String type) throws IOException {
    4.27 +                out.append('"').append(type).append("\" : {\n");
    4.28 +                cnt = 0;
    4.29 +            }
    4.30 +
    4.31 +            @Override
    4.32 +            protected void visitAnnotationEnd(String type) throws IOException {
    4.33 +                out.append("\n}\n");
    4.34 +            }
    4.35 +            
    4.36 +            @Override
    4.37 +            protected void visitAttr(String type, String attr, String value) 
    4.38 +            throws IOException {
    4.39 +                if (cnt++ > 0) {
    4.40 +                    out.append(",\n");
    4.41 +                }
    4.42 +                out.append(attr).append(" : ").append(value);
    4.43 +            }
    4.44 +        };
    4.45 +        ap.parse(data, cd);
    4.46 +    }
    4.47  }
     5.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Sun Dec 02 06:34:14 2012 +0100
     5.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Sun Dec 02 12:26:14 2012 +0100
     5.3 @@ -74,6 +74,9 @@
     5.4      @Test public void jsNewInstance() throws Exception {
     5.5          assertExec("Check new instance", Classes.class, "newInstanceZ", Double.valueOf(1));
     5.6      }
     5.7 +    @Test public void jsAnnotation() throws Exception {
     5.8 +        assertExec("Check class annotation", Classes.class, "getMarkerI", Double.valueOf(10));
     5.9 +    }
    5.10      
    5.11      private static CharSequence codeSeq;
    5.12      private static Invocable code;
     6.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java	Sun Dec 02 06:34:14 2012 +0100
     6.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java	Sun Dec 02 12:26:14 2012 +0100
     6.3 @@ -24,6 +24,7 @@
     6.4   *
     6.5   * @author Jaroslav Tulach <jtulach@netbeans.org>
     6.6   */
     6.7 +@ClassesMarker(number = 10)
     6.8  public class Classes {
     6.9      public static boolean equalsClassesOfExceptions() {
    6.10          return MalformedURLException.class.getSuperclass() == IOException.class;
    6.11 @@ -54,4 +55,11 @@
    6.12          }
    6.13          throw new IllegalStateException("Not a subtype: " + ioe);
    6.14      }
    6.15 +    public static int getMarker() {
    6.16 +        if (!Classes.class.isAnnotationPresent(ClassesMarker.class)) {
    6.17 +            return -2;
    6.18 +        }
    6.19 +        ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class);
    6.20 +        return cm == null ? -1 : cm.number();
    6.21 +    }
    6.22  }
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java	Sun Dec 02 12:26:14 2012 +0100
     7.3 @@ -0,0 +1,30 @@
     7.4 +/**
     7.5 + * Back 2 Browser Bytecode Translator
     7.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     7.7 + *
     7.8 + * This program is free software: you can redistribute it and/or modify
     7.9 + * it under the terms of the GNU General Public License as published by
    7.10 + * the Free Software Foundation, version 2 of the License.
    7.11 + *
    7.12 + * This program is distributed in the hope that it will be useful,
    7.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.15 + * GNU General Public License for more details.
    7.16 + *
    7.17 + * You should have received a copy of the GNU General Public License
    7.18 + * along with this program. Look for COPYING file in the top folder.
    7.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    7.20 + */
    7.21 +package org.apidesign.vm4brwsr;
    7.22 +
    7.23 +import java.lang.annotation.Retention;
    7.24 +import java.lang.annotation.RetentionPolicy;
    7.25 +
    7.26 +/**
    7.27 + *
    7.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    7.29 + */
    7.30 +@Retention(RetentionPolicy.RUNTIME)
    7.31 +public @interface ClassesMarker {
    7.32 +    int number();
    7.33 +}