1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compacttest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionAnnotationTest.java Sat Mar 19 10:31:13 2016 +0100
1.3 @@ -0,0 +1,117 @@
1.4 +/**
1.5 + * Back 2 Browser Bytecode Translator
1.6 + * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, version 2 of the License.
1.11 + *
1.12 + * This program is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 + * GNU General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU General Public License
1.18 + * along with this program. Look for COPYING file in the top folder.
1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
1.20 + */
1.21 +package org.apidesign.bck2brwsr.tck;
1.22 +
1.23 +import java.lang.annotation.Retention;
1.24 +import java.lang.annotation.RetentionPolicy;
1.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
1.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
1.27 +import org.testng.annotations.Factory;
1.28 +
1.29 +/**
1.30 + *
1.31 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.32 + */
1.33 +public class ReflectionAnnotationTest {
1.34 + @Retention(RetentionPolicy.RUNTIME)
1.35 + @interface Ann {
1.36 + int integer() default 33;
1.37 + double dbl() default 33.3;
1.38 + String string() default "Ahoj";
1.39 + E enums() default E.B;
1.40 + Class<?> type() default String.class;
1.41 + }
1.42 +
1.43 + @interface AnnAnn {
1.44 + Ann ann() default @Ann(
1.45 + dbl = 44.4,
1.46 + enums = E.A,
1.47 + string = "Hi",
1.48 + integer = 44
1.49 + );
1.50 + }
1.51 +
1.52 + @Ann
1.53 + @AnnAnn
1.54 + class D {
1.55 + }
1.56 +
1.57 + @Ann(type = String.class)
1.58 + @AnnAnn(ann = @Ann(string = "Ciao"))
1.59 + enum E {
1.60 + A, B
1.61 + };
1.62 +
1.63 +
1.64 + @Compare public String annoClass() throws Exception {
1.65 + Retention r = Ann.class.getAnnotation(Retention.class);
1.66 + assert r != null : "Annotation is present";
1.67 + assert r.value() == RetentionPolicy.RUNTIME : "Policy value is OK: " + r.value();
1.68 + return r.annotationType().getName();
1.69 + }
1.70 +
1.71 + @Compare public boolean isAnnotation() {
1.72 + return Ann.class.isAnnotation();
1.73 + }
1.74 + @Compare public boolean isNotAnnotation() {
1.75 + return String.class.isAnnotation();
1.76 + }
1.77 + @Compare public boolean isNotAnnotationEnum() {
1.78 + return E.class.isAnnotation();
1.79 + }
1.80 +
1.81 + @Compare public int intDefaultAttrIsRead() {
1.82 + return D.class.getAnnotation(Ann.class).integer();
1.83 + }
1.84 +
1.85 + @Compare public double doubleDefaultAttrIsRead() {
1.86 + return D.class.getAnnotation(Ann.class).dbl();
1.87 + }
1.88 +
1.89 + @Compare public String stringDefaultAttrIsRead() {
1.90 + return D.class.getAnnotation(Ann.class).string();
1.91 + }
1.92 +
1.93 + @Compare public String enumDefaultAttrIsRead() {
1.94 + return D.class.getAnnotation(Ann.class).enums().toString();
1.95 + }
1.96 +
1.97 + @Compare public String classDefaultAttrIsRead() {
1.98 + return D.class.getAnnotation(Ann.class).type().getName();
1.99 + }
1.100 +
1.101 + @Compare public String classAttrIsRead() {
1.102 + return E.class.getAnnotation(Ann.class).type().getName();
1.103 + }
1.104 +
1.105 +// @Compare public String defaultAnnotationAttrIsRead() {
1.106 +// final Ann ann = D.class.getAnnotation(AnnAnn.class).ann();
1.107 +// return ann.string() + ann.dbl() + ann.enums() + ann.integer() + ann.type();
1.108 +// }
1.109 +//
1.110 +// @Compare public String annotationAttrIsRead() {
1.111 +// final Ann ann = E.class.getAnnotation(AnnAnn.class).ann();
1.112 +// return ann.string();
1.113 +// }
1.114 +
1.115 + @Factory
1.116 + public static Object[] create() {
1.117 + return VMTest.create(ReflectionAnnotationTest.class);
1.118 + }
1.119 +
1.120 +}
2.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/AnnotationImpl.java Sat Mar 19 10:28:03 2016 +0100
2.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/AnnotationImpl.java Sat Mar 19 10:31:13 2016 +0100
2.3 @@ -38,11 +38,20 @@
2.4 }
2.5
2.6 @JavaScriptBody(args = { "a", "n", "arr", "values" }, body = ""
2.7 - + "function f(val, prop, clazz) {\n"
2.8 + + "function r(anno, val, prop, m) {\n"
2.9 + + " var v = val[prop];\n"
2.10 + + " if (typeof v === 'undefined') {\n"
2.11 + + " var cls = anno.fld_org_apidesign_bck2brwsr_emul_reflect_AnnotationImpl_type.cnstr;\n"
2.12 + + " try { throw 'x'; } catch (errr) {};\n"
2.13 + + " v = cls.prototype[m]();\n"
2.14 + + " }\n"
2.15 + + " return v;\n"
2.16 + + "}\n"
2.17 + + "function f(val, prop, clazz, m) {\n"
2.18 + " return function() {\n"
2.19 - + " if (clazz == null) return val[prop];\n"
2.20 + + " if (clazz == null) return r(this, val, prop, m);\n"
2.21 + " if (clazz.isArray__Z()) {\n"
2.22 - + " var valarr = val[prop];\n"
2.23 + + " var valarr = r(this, val, prop, m);\n"
2.24 + " var cmp = clazz.getComponentType__Ljava_lang_Class_2();\n"
2.25 + " var retarr = vm.java_lang_reflect_Array(false).newInstance__Ljava_lang_Object_2Ljava_lang_Class_2I(cmp, valarr.length);\n"
2.26 + " for (var i = 0; i < valarr.length; i++) {\n"
2.27 @@ -50,14 +59,14 @@
2.28 + " }\n"
2.29 + " return retarr;\n"
2.30 + " }\n"
2.31 - + " return CLS.prototype.c__Ljava_lang_Object_2Ljava_lang_Class_2Ljava_lang_Object_2(clazz, val[prop]);\n"
2.32 + + " return CLS.prototype.c__Ljava_lang_Object_2Ljava_lang_Class_2Ljava_lang_Object_2(clazz, r(this, val, prop, m));\n"
2.33 + " };\n"
2.34 + "}\n"
2.35 + "for (var i = 0; i < arr.length; i += 3) {\n"
2.36 + " var m = arr[i];\n"
2.37 + " var p = arr[i + 1];\n"
2.38 + " var c = arr[i + 2];\n"
2.39 - + " a[m] = f(values, p, c);\n"
2.40 + + " a[m] = f(values, p, c, m);\n"
2.41 + "}\n"
2.42 + "a['$instOf_' + n] = true;\n"
2.43 + "return a;"
3.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sat Mar 19 10:28:03 2016 +0100
3.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sat Mar 19 10:31:13 2016 +0100
3.3 @@ -78,6 +78,7 @@
3.4 public static final int ACC_STRICT = 0x00000800;
3.5 public static final int ACC_EXPLICIT = 0x00001000;
3.6 public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute
3.7 + private static final int ACC_ANNOTATION = 0x00020000;
3.8
3.9 /* Type codes for StackMap attribute */
3.10 public static final int ITEM_Bogus =0; // an unknown or uninitialized value
3.11 @@ -356,14 +357,22 @@
3.12 }
3.13
3.14 protected void visitAttr(
3.15 - String annoType, String attr, String attrType, String value) throws IOException {
3.16 + String annoType, String attr, String attrType, String value
3.17 + ) throws IOException {
3.18 }
3.19
3.20 protected void visitEnumAttr(
3.21 - String annoType, String attr, String attrType, String value) throws IOException {
3.22 + String annoType, String attr, String attrType, String value
3.23 + ) throws IOException {
3.24 visitAttr(annoType, attr, attrType, value);
3.25 }
3.26
3.27 + protected void visitClassAttr(
3.28 + String annoType, String attr, String className
3.29 + ) throws IOException {
3.30 + visitAttr(annoType, attr, className, className);
3.31 + }
3.32 +
3.33 /**
3.34 * Initialize the parsing with constant pool from
3.35 * <code>cd</code>.
3.36 @@ -404,6 +413,16 @@
3.37 }
3.38 }
3.39
3.40 + public void parseDefault(byte[] defaultAttribute, ClassData cd) throws IOException {
3.41 + ByteArrayInputStream is = new ByteArrayInputStream(defaultAttribute);
3.42 + DataInputStream dis = new DataInputStream(is);
3.43 + try {
3.44 + readValue(dis, cd, null, null);
3.45 + } finally {
3.46 + is.close();
3.47 + }
3.48 + }
3.49 +
3.50 private void readValue(
3.51 DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException {
3.52 char type = (char) dis.readByte();
3.53 @@ -425,6 +444,8 @@
3.54 visitAttr(typeName, attrName, attrType, val);
3.55 } else if (type == 'c') {
3.56 int cls = dis.readUnsignedShort();
3.57 + String attrType = cd.stringValue(cls, textual);
3.58 + visitClassAttr(typeName, attrName, attrType);
3.59 } else if (type == '[') {
3.60 int cnt = dis.readUnsignedShort();
3.61 for (int i = 0; i < cnt; i++) {
3.62 @@ -875,6 +896,10 @@
3.63 return false;
3.64 }
3.65
3.66 + public boolean isAnnotation() {
3.67 + return (access & ACC_ANNOTATION) != 0;
3.68 + }
3.69 +
3.70 /**
3.71 * Returns true if this member is public, false otherwise.
3.72 */
3.73 @@ -1687,6 +1712,7 @@
3.74 int max_stack, max_locals;
3.75 boolean isSynthetic = false;
3.76 boolean isDeprecated = false;
3.77 + private AttrData annotationDefault;
3.78
3.79 public MethodData(ClassData cls) {
3.80 this.cls = cls;
3.81 @@ -1737,6 +1763,12 @@
3.82 attr.read(attr_name_index);
3.83 attrs.addElement(attr);
3.84 break readAttr;
3.85 + } else if (attr_name.equals("AnnotationDefault")) {
3.86 + AttrData attr = new AttrData(cls);
3.87 + attr.read(attr_name_index, in);
3.88 + attrs.addElement(attr);
3.89 + annotationDefault = attr;
3.90 + break readAttr;
3.91 }
3.92 }
3.93 AttrData attr = new AttrData(cls);
3.94 @@ -1994,6 +2026,10 @@
3.95 return code_attrs;
3.96 }
3.97
3.98 + byte[] getDefaultAttribute() {
3.99 + return annotationDefault == null ? null : annotationDefault.getData();
3.100 + }
3.101 +
3.102 /**
3.103 * Return true if method id synthetic.
3.104 */
4.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sat Mar 19 10:28:03 2016 +0100
4.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sat Mar 19 10:31:13 2016 +0100
4.3 @@ -288,7 +288,8 @@
4.4 byte[] runAnno = m.findAnnotationData(false);
4.5 if (runAnno != null) {
4.6 append("\n m.anno = {");
4.7 - generateAnno(jc, runAnno);
4.8 + AnnotationParser ap = new GenerateAnno(true, false);
4.9 + ap.parse(runAnno, jc);
4.10 append("\n };");
4.11 }
4.12 append("\n m.access = " + m.getAccess()).append(";");
4.13 @@ -343,7 +344,8 @@
4.14 byte[] classAnno = jc.findAnnotationData(false);
4.15 if (classAnno != null) {
4.16 append("\n CLS.$class.anno = {");
4.17 - generateAnno(jc, classAnno);
4.18 + AnnotationParser ap = new GenerateAnno(true, false);
4.19 + ap.parse(classAnno, jc);
4.20 append("\n };");
4.21 }
4.22 for (String init : toInitilize.toArray()) {
4.23 @@ -453,10 +455,18 @@
4.24
4.25 final byte[] byteCodes = m.getCode();
4.26 if (byteCodes == null) {
4.27 - if (debug(" throw 'no code found for ")) {
4.28 - this
4.29 - .append(jc.getClassName()).append('.')
4.30 - .append(m.getName()).append("';\n");
4.31 + byte[] defaultAttr = m.getDefaultAttribute();
4.32 + if (defaultAttr != null) {
4.33 + append(" return ");
4.34 + AnnotationParser ap = new GenerateAnno(true, false);
4.35 + ap.parseDefault(defaultAttr, jc);
4.36 + append(";\n");
4.37 + } else {
4.38 + if (debug(" throw 'no code found for ")) {
4.39 + this
4.40 + .append(jc.getClassName()).append('.')
4.41 + .append(m.getName()).append("';\n");
4.42 + }
4.43 }
4.44 if (defineProp) {
4.45 append("}});");
4.46 @@ -2156,81 +2166,6 @@
4.47 return " = null;";
4.48 }
4.49
4.50 - private void generateAnno(ClassData cd, byte[] data) throws IOException {
4.51 - AnnotationParser ap = new AnnotationParser(true, false) {
4.52 - int[] cnt = new int[32];
4.53 - int depth;
4.54 -
4.55 - @Override
4.56 - protected void visitAnnotationStart(String attrType, boolean top) throws IOException {
4.57 - final String slashType = attrType.substring(1, attrType.length() - 1);
4.58 - requireReference(slashType);
4.59 -
4.60 - if (cnt[depth]++ > 0) {
4.61 - append(",");
4.62 - }
4.63 - if (top) {
4.64 - append('"').append(attrType).append("\" : ");
4.65 - }
4.66 - append("{\n");
4.67 - cnt[++depth] = 0;
4.68 - }
4.69 -
4.70 - @Override
4.71 - protected void visitAnnotationEnd(String type, boolean top) throws IOException {
4.72 - append("\n}\n");
4.73 - depth--;
4.74 - }
4.75 -
4.76 - @Override
4.77 - protected void visitValueStart(String attrName, char type) throws IOException {
4.78 - if (cnt[depth]++ > 0) {
4.79 - append(",\n");
4.80 - }
4.81 - cnt[++depth] = 0;
4.82 - if (attrName != null) {
4.83 - append('"').append(attrName).append("\" : ");
4.84 - }
4.85 - if (type == '[') {
4.86 - append("[");
4.87 - }
4.88 - }
4.89 -
4.90 - @Override
4.91 - protected void visitValueEnd(String attrName, char type) throws IOException {
4.92 - if (type == '[') {
4.93 - append("]");
4.94 - }
4.95 - depth--;
4.96 - }
4.97 -
4.98 - @Override
4.99 - protected void visitAttr(String type, String attr, String attrType, String value)
4.100 - throws IOException {
4.101 - if (attr == null && value == null) {
4.102 - return;
4.103 - }
4.104 - append(value);
4.105 - }
4.106 -
4.107 - @Override
4.108 - protected void visitEnumAttr(String type, String attr, String attrType, String value)
4.109 - throws IOException {
4.110 - final String slashType = attrType.substring(1, attrType.length() - 1);
4.111 - requireReference(slashType);
4.112 -
4.113 - final String cn = mangleClassName(slashType);
4.114 - append(accessClassFalse(cn))
4.115 - .append("['valueOf__L").
4.116 - append(cn).
4.117 - append("_2Ljava_lang_String_2']('").
4.118 - append(value).
4.119 - append("')");
4.120 - }
4.121 - };
4.122 - ap.parse(data, cd);
4.123 - }
4.124 -
4.125 private static String outputArg(Appendable out, String[] args, int indx) throws IOException {
4.126 final String name = args[indx];
4.127 if (name == null) {
4.128 @@ -2505,4 +2440,88 @@
4.129 private static void println(String msg) {
4.130 System.err.println(msg);
4.131 }
4.132 +
4.133 + private class GenerateAnno extends AnnotationParser {
4.134 + public GenerateAnno(boolean textual, boolean iterateArray) {
4.135 + super(textual, iterateArray);
4.136 + }
4.137 + int[] cnt = new int[32];
4.138 + int depth;
4.139 +
4.140 + @Override
4.141 + protected void visitAnnotationStart(String attrType, boolean top) throws IOException {
4.142 + final String slashType = attrType.substring(1, attrType.length() - 1);
4.143 + requireReference(slashType);
4.144 +
4.145 + if (cnt[depth]++ > 0) {
4.146 + append(",");
4.147 + }
4.148 + if (top) {
4.149 + append('"').append(attrType).append("\" : ");
4.150 + }
4.151 + append("{\n");
4.152 + cnt[++depth] = 0;
4.153 + }
4.154 +
4.155 + @Override
4.156 + protected void visitAnnotationEnd(String type, boolean top) throws IOException {
4.157 + append("\n}\n");
4.158 + depth--;
4.159 + }
4.160 +
4.161 + @Override
4.162 + protected void visitValueStart(String attrName, char type) throws IOException {
4.163 + if (cnt[depth]++ > 0) {
4.164 + append(",\n");
4.165 + }
4.166 + cnt[++depth] = 0;
4.167 + if (attrName != null) {
4.168 + append('"').append(attrName).append("\" : ");
4.169 + }
4.170 + if (type == '[') {
4.171 + append("[");
4.172 + }
4.173 + }
4.174 +
4.175 + @Override
4.176 + protected void visitValueEnd(String attrName, char type) throws IOException {
4.177 + if (type == '[') {
4.178 + append("]");
4.179 + }
4.180 + depth--;
4.181 + }
4.182 +
4.183 + @Override
4.184 + protected void visitAttr(String type, String attr, String attrType, String value)
4.185 + throws IOException {
4.186 + if (attr == null && value == null) {
4.187 + return;
4.188 + }
4.189 + append(value);
4.190 + }
4.191 +
4.192 + @Override
4.193 + protected void visitEnumAttr(String type, String attr, String attrType, String value)
4.194 + throws IOException {
4.195 + final String slashType = attrType.substring(1, attrType.length() - 1);
4.196 + requireReference(slashType);
4.197 +
4.198 + final String cn = mangleClassName(slashType);
4.199 + append(accessClassFalse(cn))
4.200 + .append("['valueOf__L").
4.201 + append(cn).
4.202 + append("_2Ljava_lang_String_2']('").
4.203 + append(value).
4.204 + append("')");
4.205 + }
4.206 +
4.207 + @Override
4.208 + protected void visitClassAttr(String annoType, String attr, String className) throws IOException {
4.209 + final String slashType = className.substring(1, className.length() - 1);
4.210 + requireReference(slashType);
4.211 +
4.212 + final String cn = mangleClassName(slashType);
4.213 + append(accessClassFalse(cn)).append(".constructor.$class");
4.214 + }
4.215 + }
4.216 }
5.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Sat Mar 19 10:28:03 2016 +0100
5.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Sat Mar 19 10:31:13 2016 +0100
5.3 @@ -87,12 +87,18 @@
5.4 @Test public void jsAnnotation() throws Exception {
5.5 assertExec("Check class annotation", Classes.class, "getMarker__I", Double.valueOf(10));
5.6 }
5.7 + @Test public void jsAnnotationDefaultValue() throws Exception {
5.8 + assertExec("Check class annotation", Classes.class, "getMarkerDefault__I", Double.valueOf(42));
5.9 + }
5.10 @Test public void jsArrayAnnotation() throws Exception {
5.11 assertExec("Check array annotation", Classes.class, "getMarkerNicknames__Ljava_lang_String_2", Classes.getMarkerNicknames());
5.12 }
5.13 @Test public void jsEnumAnnotation() throws Exception {
5.14 assertExec("Check enum annotation", Classes.class, "getMarkerE__Ljava_lang_String_2", Classes.getMarkerE());
5.15 }
5.16 + @Test public void jsEnumAnnotationDefault() throws Exception {
5.17 + assertExec("Check enum annotation", Classes.class, "getMarkerED__Ljava_lang_String_2", Classes.getMarkerED());
5.18 + }
5.19 @Test public void jsRetentionAnnotation() throws Exception {
5.20 assertExec("Check enum annotation", Classes.class, "getRetention__Ljava_lang_String_2", Classes.getRetention());
5.21 }
5.22 @@ -108,6 +114,12 @@
5.23 @Test public void jsInnerAnnotationFromArray() throws Exception {
5.24 assertExec("Check inner annotation", Classes.class, "getInnerNamers__I", Double.valueOf(Classes.getInnerNamers()));
5.25 }
5.26 + @Test public void jsAnnotationClassAttr() throws Exception {
5.27 + assertExec("Check annotation with class attribute", Classes.class, "self__I", 1);
5.28 + }
5.29 + @Test public void jsAnnotationDefaultClassAttr() throws Exception {
5.30 + assertExec("Check annotation with class attribute", Classes.class, "defaultSelf__I", 1);
5.31 + }
5.32 @Test public void javaInvokeMethod() throws Exception {
5.33 assertEquals(Classes.reflectiveMethodCall(true, "name"), "java.io.IOException", "Calls the name() method via reflection");
5.34 }
6.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Sat Mar 19 10:28:03 2016 +0100
6.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Sat Mar 19 10:31:13 2016 +0100
6.3 @@ -67,6 +67,33 @@
6.4 public static String name() {
6.5 return IOException.class.getName().toString();
6.6 }
6.7 +
6.8 + @ClassesMarker(self = Self.class, number = 42, nicknames = {})
6.9 + public static class Self {
6.10 + }
6.11 +
6.12 + @ClassesMarker(number = 42, nicknames = {})
6.13 + public static class DefaultSelf {
6.14 + }
6.15 +
6.16 + public static int self() {
6.17 + ClassesMarker cm = Self.class.getAnnotation(ClassesMarker.class);
6.18 + if (cm.self() == Self.class) {
6.19 + return 1;
6.20 + } else {
6.21 + return 0;
6.22 + }
6.23 + }
6.24 +
6.25 + public static int defaultSelf() {
6.26 + ClassesMarker cm = DefaultSelf.class.getAnnotation(ClassesMarker.class);
6.27 + if (cm.self() == Object.class) {
6.28 + return 1;
6.29 + } else {
6.30 + throw new IllegalStateException("" + cm.self());
6.31 + }
6.32 + }
6.33 +
6.34 public static String simpleName() {
6.35 return IOException.class.getSimpleName();
6.36 }
6.37 @@ -103,6 +130,11 @@
6.38 assert !((Object)cm instanceof Class) : "Is not Class " + cm;
6.39 return cm == null ? -1 : cm.number();
6.40 }
6.41 + public static int getMarkerDefault() {
6.42 + try { throw new IllegalStateException(); } catch (Exception e) {}
6.43 + ClassesMarker cm = CD.class.getAnnotation(ClassesMarker.class);
6.44 + return cm == null ? -1 : cm.number();
6.45 + }
6.46 public static String getMarkerNicknames() {
6.47 ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class);
6.48 if (cm == null) {
6.49 @@ -149,6 +181,17 @@
6.50 }
6.51 return cm.count().name();
6.52 }
6.53 +
6.54 + @ClassesMarker(nicknames = {})
6.55 + class CD {
6.56 + }
6.57 + public static String getMarkerED() {
6.58 + ClassesMarker cm = CD.class.getAnnotation(ClassesMarker.class);
6.59 + if (cm == null) {
6.60 + return null;
6.61 + }
6.62 + return cm.count().name();
6.63 + }
6.64 public static String getNamer(boolean direct) {
6.65 if (direct) {
6.66 ClassesNamer cm = Classes.class.getAnnotation(ClassesNamer.class);
7.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java Sat Mar 19 10:28:03 2016 +0100
7.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java Sat Mar 19 10:31:13 2016 +0100
7.3 @@ -26,9 +26,10 @@
7.4 */
7.5 @Retention(RetentionPolicy.RUNTIME)
7.6 public @interface ClassesMarker {
7.7 - int number();
7.8 + int number() default 42;
7.9 String[] nicknames();
7.10 E count() default E.ONE;
7.11 + Class<?> self() default Object.class;
7.12
7.13 enum E {
7.14 ONE, TWO;