# HG changeset patch # User Jaroslav Tulach # Date 1354698238 -3600 # Node ID 2e2e6f946208fa38d21826b0c3ffe7f515b345db # Parent 20c55abd6748f9fbce5cdef2e045adc949018959 Can obtain annotation from a method diff -r 20c55abd6748 -r 2e2e6f946208 emul/src/main/java/java/lang/AnnotationImpl.java --- a/emul/src/main/java/java/lang/AnnotationImpl.java Wed Dec 05 09:31:36 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * 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 = "" - + "function f(v, p) {\n" - + " var val = v;\n" - + " var prop = p;\n" - + " return function() {\n" - + " return val[prop];\n" - + " };\n" - + "}\n" - + "var props = Object.getOwnPropertyNames(values);\n" - + "for (var i = 0; i < props.length; i++) {\n" - + " var p = props[i];\n" - + " a[p] = new f(values, p);\n" - + "}\n" - + "a['$instOf_' + n] = true;\n" - + "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); - } - - static Annotation[] create(Object anno) { - String[] names = findNames(anno); - Annotation[] ret = new Annotation[names.length]; - for (int i = 0; i < names.length; i++) { - String n = names[i].substring(1, names[i].length() - 1).replace('/', '_'); - ret[i] = create(new AnnotationImpl(), n, findData(anno, names[i])); - } - return ret; - } - @JavaScriptBody(args = "anno", body = - "var arr = new Array();" - + "var props = Object.getOwnPropertyNames(anno);\n" - + "for (var i = 0; i < props.length; i++) {\n" - + " var p = props[i];\n" - + " arr.push(p);" - + "}" - + "return arr;" - ) - private static String[] findNames(Object anno) { - throw new UnsupportedOperationException(); - } - - @JavaScriptBody(args={ "anno", "p"}, body="return anno[p];") - private static Object findData(Object anno, String p) { - throw new UnsupportedOperationException(); - } -} diff -r 20c55abd6748 -r 2e2e6f946208 emul/src/main/java/java/lang/Class.java --- a/emul/src/main/java/java/lang/Class.java Wed Dec 05 09:31:36 2012 +0100 +++ b/emul/src/main/java/java/lang/Class.java Wed Dec 05 10:03:58 2012 +0100 @@ -25,6 +25,7 @@ package java.lang; +import org.apidesign.bck2brwsr.emul.AnnotationImpl; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -1025,7 +1026,7 @@ body = "if (self.anno) {" + " return self.anno['L' + ac.jvmName + ';'];" - + "}" + + "} else return null;" ) private Object getAnnotationData(Class annotationClass) { throw new UnsupportedOperationException(); diff -r 20c55abd6748 -r 2e2e6f946208 emul/src/main/java/java/lang/reflect/Method.java --- a/emul/src/main/java/java/lang/reflect/Method.java Wed Dec 05 09:31:36 2012 +0100 +++ b/emul/src/main/java/java/lang/reflect/Method.java Wed Dec 05 10:03:58 2012 +0100 @@ -27,6 +27,7 @@ import java.lang.annotation.Annotation; import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.emul.AnnotationImpl; /** * A {@code Method} provides information about, and access to, a single method @@ -535,15 +536,23 @@ return Modifier.isSynthetic(getModifiers()); } + @JavaScriptBody(args = { "self", "ac" }, + body = + "if (self.fld_data.anno) {" + + " return self.fld_data.anno['L' + ac.jvmName + ';'];" + + "} else return null;" + ) + private Object getAnnotationData(Class annotationClass) { + throw new UnsupportedOperationException(); + } + /** * @throws NullPointerException {@inheritDoc} * @since 1.5 */ public T getAnnotation(Class annotationClass) { - if (annotationClass == null) - throw new NullPointerException(); - - throw new UnsupportedOperationException(); + Object data = getAnnotationData(annotationClass); + return data == null ? null : AnnotationImpl.create(annotationClass, data); } /** diff -r 20c55abd6748 -r 2e2e6f946208 emul/src/main/java/org/apidesign/bck2brwsr/emul/AnnotationImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/org/apidesign/bck2brwsr/emul/AnnotationImpl.java Wed Dec 05 10:03:58 2012 +0100 @@ -0,0 +1,68 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.bck2brwsr.emul; + +import java.lang.annotation.Annotation; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +public final class AnnotationImpl implements Annotation { + public Class annotationType() { + return getClass(); + } + + @JavaScriptBody(args = { "a", "n", "values" }, body = "" + + "function f(v, p) {\n" + + " var val = v;\n" + + " var prop = p;\n" + + " return function() {\n" + + " return val[prop];\n" + + " };\n" + + "}\n" + + "var props = Object.getOwnPropertyNames(values);\n" + + "for (var i = 0; i < props.length; i++) {\n" + + " var p = props[i];\n" + + " a[p] = new f(values, p);\n" + + "}\n" + + "a['$instOf_' + n] = true;\n" + + "return a;" + ) + private static T create(AnnotationImpl a, String n, Object values) { + return null; + } + public static T create(Class annoClass, Object values) { + return create(new AnnotationImpl(), annoClass.getName().replace('.', '_'), values); + } + + public static Annotation[] create(Object anno) { + String[] names = findNames(anno); + Annotation[] ret = new Annotation[names.length]; + for (int i = 0; i < names.length; i++) { + String n = names[i].substring(1, names[i].length() - 1).replace('/', '_'); + ret[i] = create(new AnnotationImpl(), n, findData(anno, names[i])); + } + return ret; + } + @JavaScriptBody(args = "anno", body = + "var arr = new Array();" + + "var props = Object.getOwnPropertyNames(anno);\n" + + "for (var i = 0; i < props.length; i++) {\n" + + " var p = props[i];\n" + + " arr.push(p);" + + "}" + + "return arr;" + ) + private static String[] findNames(Object anno) { + throw new UnsupportedOperationException(); + } + + @JavaScriptBody(args={ "anno", "p"}, body="return anno[p];") + private static Object findData(Object anno, String p) { + throw new UnsupportedOperationException(); + } +} diff -r 20c55abd6748 -r 2e2e6f946208 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Dec 05 09:31:36 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Dec 05 10:03:58 2012 +0100 @@ -121,10 +121,17 @@ } continue; } + String mn; if (m.isStatic()) { - generateStaticMethod("\n c.", m, toInitilize); + mn = generateStaticMethod("\n c.", m, toInitilize); } else { - generateInstanceMethod("\n c.", m); + mn = generateInstanceMethod("\n c.", m); + } + byte[] runAnno = m.findAnnotationData(false); + if (runAnno != null) { + out.append("\n c.").append(mn).append(".anno = {"); + generateAnno(jc, out, runAnno); + out.append("\n };"); } } out.append("\n c.constructor = CLS;"); @@ -175,9 +182,10 @@ } return sb.toString(); } - private void generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException { - if (javaScriptBody(prefix, m, true)) { - return; + private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException { + String jsb = javaScriptBody(prefix, m, true); + if (jsb != null) { + return jsb; } StringBuilder argsCnt = new StringBuilder(); final String mn = findMethodName(m, argsCnt); @@ -212,11 +220,13 @@ out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n"); } out.append("};"); + return mn; } - private void generateInstanceMethod(String prefix, MethodData m) throws IOException { - if (javaScriptBody(prefix, m, false)) { - return; + private String generateInstanceMethod(String prefix, MethodData m) throws IOException { + String jsb = javaScriptBody(prefix, m, false); + if (jsb != null) { + return jsb; } StringBuilder argsCnt = new StringBuilder(); final String mn = findMethodName(m, argsCnt); @@ -246,6 +256,7 @@ out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n"); } out.append("};"); + return mn; } private void produceCode(byte[] byteCodes) throws IOException { @@ -1024,10 +1035,10 @@ return s; } - private boolean javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException { + private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException { byte[] arr = m.findAnnotationData(true); if (arr == null) { - return false; + return null; } final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;"; class P extends AnnotationParser { @@ -1055,10 +1066,11 @@ P p = new P(); p.parse(arr, jc); if (p.body == null) { - return false; + return null; } StringBuilder cnt = new StringBuilder(); - out.append(prefix).append(findMethodName(m, cnt)); + final String mn = findMethodName(m, cnt); + out.append(prefix).append(mn); out.append(" = function("); String space; int index; @@ -1079,7 +1091,7 @@ out.append(") {").append("\n"); out.append(p.body); out.append("\n}\n"); - return true; + return mn; } private static String className(ClassData jc) { //return jc.getName().getInternalName().replace('/', '_'); @@ -1155,6 +1167,9 @@ @Override protected void visitAttr(String type, String attr, String attrType, String value) throws IOException { + if (attr == null) { + return; + } if (cnt++ > 0) { out.append(",\n"); } diff -r 20c55abd6748 -r 2e2e6f946208 vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Wed Dec 05 09:31:36 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Wed Dec 05 10:03:58 2012 +0100 @@ -101,6 +101,15 @@ "java.io.IOException", false, "name" ); } + @Test public void javaAnnotatedMethod() throws Exception { + assertEquals(Classes.reflectiveMethodCall(false, null), "java.io.IOException", "Calls the name() method via reflection"); + } + @Test public void jsAnnotatedMethod() throws Exception { + assertExec("Calls the name() method via reflection", Classes.class, + "reflectiveMethodCall__Ljava_lang_Object_2ZLjava_lang_String_2", + "java.io.IOException", false, null + ); + } private static CharSequence codeSeq; private static Invocable code;