# HG changeset patch # User Jaroslav Tulach # Date 1354447574 -3600 # Node ID bf0a77f029c41f1e052a184c47dae492af600133 # Parent a2f1380f8a28799a7d8ef2138bbffabde8f56114 Initial support for runtime annotations diff -r a2f1380f8a28 -r bf0a77f029c4 emul/src/main/java/java/lang/AnnotationImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/lang/AnnotationImpl.java Sun Dec 02 12:26:14 2012 +0100 @@ -0,0 +1,33 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package java.lang; + +import java.lang.annotation.Annotation; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +final class AnnotationImpl implements Annotation { + public Class annotationType() { + return getClass(); + } + + @JavaScriptBody(args = { "a", "n", "values" }, body = + "var v = values;" + + "for (p in values) {" + + " a[p + 'I'] = function() { return v[p]; }" + + "}" + + "a['$instOf_' + n] = true;" + + "return a;" + ) + private static T create(AnnotationImpl a, String n, Object values) { + return null; + } + static T create(Class annoClass, Object values) { + return create(new AnnotationImpl(), annoClass.getName().replace('.', '_'), values); + } +} diff -r a2f1380f8a28 -r bf0a77f029c4 emul/src/main/java/java/lang/Class.java --- a/emul/src/main/java/java/lang/Class.java Sun Dec 02 06:34:14 2012 +0100 +++ b/emul/src/main/java/java/lang/Class.java Sun Dec 02 12:26:14 2012 +0100 @@ -774,14 +774,28 @@ * @throws NullPointerException {@inheritDoc} * @since 1.5 */ + @JavaScriptBody(args = { "self", "ac" }, + body = + "if (self.anno) {" + + " return self.anno['L' + ac.jvmName + ';'];" + + "}" + ) + private Object getAnnotationData(Class annotationClass) { + throw new UnsupportedOperationException(); + } public A getAnnotation(Class annotationClass) { - throw new UnsupportedOperationException(); + Object data = getAnnotationData(annotationClass); + return data == null ? null : AnnotationImpl.create(annotationClass, data); } /** * @throws NullPointerException {@inheritDoc} * @since 1.5 */ + @JavaScriptBody(args = { "self", "ac" }, + body = "if (self.anno && self.anno['L' + ac.jvmName + ';']) { return true; }" + + "else return false;" + ) public boolean isAnnotationPresent( Class annotationClass) { if (annotationClass == null) diff -r a2f1380f8a28 -r bf0a77f029c4 javap/src/main/java/org/apidesign/javap/AnnotationParser.java --- a/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Sun Dec 02 06:34:14 2012 +0100 +++ b/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Sun Dec 02 12:26:14 2012 +0100 @@ -37,7 +37,15 @@ protected AnnotationParser() { } - protected void visitAttr(String type, String attr, String value) { + protected void visitAnnotationStart(String type) throws IOException { + } + + protected void visitAnnotationEnd(String type) throws IOException { + } + + protected void visitAttr( + String type, String attr, String value + ) throws IOException { } /** Initialize the parsing with constant pool from cd. @@ -66,11 +74,13 @@ private void readAnno(DataInputStream dis, ClassData cd) throws IOException { int type = dis.readUnsignedShort(); String typeName = cd.StringValue(type); + visitAnnotationStart(typeName); int cnt = dis.readUnsignedShort(); for (int i = 0; i < cnt; i++) { String attrName = cd.StringValue(dis.readUnsignedShort()); readValue(dis, cd, typeName, attrName); } + visitAnnotationEnd(typeName); } private void readValue(DataInputStream dis, ClassData cd, String typeName, String attrName) diff -r a2f1380f8a28 -r bf0a77f029c4 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Dec 02 06:34:14 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Dec 02 12:26:14 2012 +0100 @@ -119,6 +119,12 @@ out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';"); out.append("\n CLS.$class.superclass = sprcls;"); out.append("\n CLS.$class.cnstr = CLS;"); + byte[] classAnno = jc.findAnnotationData(false); + if (classAnno != null) { + out.append("\n CLS.$class.anno = {"); + generateAnno(jc, out, classAnno); + out.append("\n };"); + } out.append("\n }"); out.append("\n if (arguments.length === 0) {"); out.append("\n if (!(this instanceof CLS)) {"); @@ -1085,4 +1091,31 @@ } return " = null;"; } + + private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException { + AnnotationParser ap = new AnnotationParser() { + int cnt; + + @Override + protected void visitAnnotationStart(String type) throws IOException { + out.append('"').append(type).append("\" : {\n"); + cnt = 0; + } + + @Override + protected void visitAnnotationEnd(String type) throws IOException { + out.append("\n}\n"); + } + + @Override + protected void visitAttr(String type, String attr, String value) + throws IOException { + if (cnt++ > 0) { + out.append(",\n"); + } + out.append(attr).append(" : ").append(value); + } + }; + ap.parse(data, cd); + } } diff -r a2f1380f8a28 -r bf0a77f029c4 vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Sun Dec 02 06:34:14 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Sun Dec 02 12:26:14 2012 +0100 @@ -74,6 +74,9 @@ @Test public void jsNewInstance() throws Exception { assertExec("Check new instance", Classes.class, "newInstanceZ", Double.valueOf(1)); } + @Test public void jsAnnotation() throws Exception { + assertExec("Check class annotation", Classes.class, "getMarkerI", Double.valueOf(10)); + } private static CharSequence codeSeq; private static Invocable code; diff -r a2f1380f8a28 -r bf0a77f029c4 vm/src/test/java/org/apidesign/vm4brwsr/Classes.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Sun Dec 02 06:34:14 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Sun Dec 02 12:26:14 2012 +0100 @@ -24,6 +24,7 @@ * * @author Jaroslav Tulach */ +@ClassesMarker(number = 10) public class Classes { public static boolean equalsClassesOfExceptions() { return MalformedURLException.class.getSuperclass() == IOException.class; @@ -54,4 +55,11 @@ } throw new IllegalStateException("Not a subtype: " + ioe); } + public static int getMarker() { + if (!Classes.class.isAnnotationPresent(ClassesMarker.class)) { + return -2; + } + ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class); + return cm == null ? -1 : cm.number(); + } } diff -r a2f1380f8a28 -r bf0a77f029c4 vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java Sun Dec 02 12:26:14 2012 +0100 @@ -0,0 +1,30 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface ClassesMarker { + int number(); +}