Hiding all generated class methods from sight of external users. Exposing only bck2brwsr entry point function
2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.vm4brwsr;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import org.apidesign.javap.AnnotationParser;
23 import org.apidesign.javap.ClassData;
24 import org.apidesign.javap.FieldData;
25 import org.apidesign.javap.MethodData;
26 import static org.apidesign.javap.RuntimeConstants.*;
28 /** Translator of the code inside class files to JavaScript.
30 * @author Jaroslav Tulach <jtulach@netbeans.org>
32 public abstract class ByteCodeToJavaScript {
36 protected ByteCodeToJavaScript(Appendable out) {
40 /* Collects additional required resources.
42 * @param internalClassName classes that were referenced and should be loaded in order the
43 * generated JavaScript code works properly. The names are in internal
44 * JVM form so String is <code>java/lang/String</code>.
46 protected abstract boolean requireReference(String internalClassName);
49 * @param resourcePath name of resources to read
51 protected abstract void requireScript(String resourcePath);
53 /** Allows subclasses to redefine what field a function representing a
54 * class gets assigned. By default it returns the suggested name followed
55 * by <code>" = "</code>;
57 * @param className suggested name of the class
59 /* protected */ String assignClass(String className) {
60 return className + " = ";
62 /* protected */ String accessClass(String classOperation) {
63 return classOperation;
67 * Converts a given class file to a JavaScript version.
69 * @param classFile input stream with code of the .class file
70 * @return the initialization code for this class, if any. Otherwise <code>null</code>
72 * @throws IOException if something goes wrong during read or write or translating
75 public String compile(InputStream classFile) throws IOException {
76 this.jc = new ClassData(classFile);
77 byte[] arrData = jc.findAnnotationData(true);
78 String[] arr = findAnnotation(arrData, jc,
79 "org.apidesign.bck2brwsr.core.ExtraJavaScript",
80 "resource", "processByteCode"
83 requireScript(arr[0]);
84 if ("0".equals(arr[1])) {
88 String[] proto = findAnnotation(arrData, jc,
89 "org.apidesign.bck2brwsr.core.JavaScriptPrototype",
90 "container", "prototype"
92 StringArray toInitilize = new StringArray();
93 final String className = className(jc);
94 out.append("\n\n").append(assignClass(className));
95 out.append("function CLS() {");
96 out.append("\n if (!CLS.prototype.$instOf_").append(className).append(") {");
97 for (FieldData v : jc.getFields()) {
99 out.append("\n CLS.").append(v.getName()).append(initField(v));
103 String sc = jc.getSuperClassName(); // with _
104 out.append("\n var pp = ").
105 append(accessClass(sc.replace('/', '_'))).append("(true);");
106 out.append("\n var p = CLS.prototype = pp;");
107 out.append("\n var c = p;");
108 out.append("\n var sprcls = pp.constructor.$class;");
110 out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";");
111 out.append("\n var c = ").append(proto[0]).append(";");
112 out.append("\n var sprcls = null;");
114 for (MethodData m : jc.getMethods()) {
115 byte[] onlyArr = m.findAnnotationData(true);
116 String[] only = findAnnotation(onlyArr, jc,
117 "org.apidesign.bck2brwsr.core.JavaScriptOnly",
121 if (only[0] != null && only[1] != null) {
122 out.append("\n p.").append(only[0]).append(" = ")
123 .append(only[1]).append(";");
129 mn = generateStaticMethod("\n c.", m, toInitilize);
131 mn = generateInstanceMethod("\n c.", m);
133 byte[] runAnno = m.findAnnotationData(false);
134 if (runAnno != null) {
135 out.append("\n c.").append(mn).append(".anno = {");
136 generateAnno(jc, out, runAnno);
140 out.append("\n c.constructor = CLS;");
141 out.append("\n c.$instOf_").append(className).append(" = true;");
142 for (String superInterface : jc.getSuperInterfaces()) {
143 out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
145 out.append("\n CLS.$class = ");
146 out.append(accessClass("java_lang_Class(true);"));
147 out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
148 out.append("\n CLS.$class.superclass = sprcls;");
149 out.append("\n CLS.$class.cnstr = CLS;");
150 byte[] classAnno = jc.findAnnotationData(false);
151 if (classAnno != null) {
152 out.append("\n CLS.$class.anno = {");
153 generateAnno(jc, out, classAnno);
157 out.append("\n if (arguments.length === 0) {");
158 out.append("\n if (!(this instanceof CLS)) {");
159 out.append("\n return new CLS();");
161 for (FieldData v : jc.getFields()) {
162 byte[] onlyArr = v.findAnnotationData(true);
163 String[] only = findAnnotation(onlyArr, jc,
164 "org.apidesign.bck2brwsr.core.JavaScriptOnly",
168 if (only[0] != null && only[1] != null) {
169 out.append("\n p.").append(only[0]).append(" = ")
170 .append(only[1]).append(";");
175 out.append("\n this.fld_").
176 append(v.getName()).append(initField(v));
179 out.append("\n return this;");
181 out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
183 StringBuilder sb = new StringBuilder();
184 for (String init : toInitilize.toArray()) {
185 sb.append("\n").append(init).append("();");
187 return sb.toString();
189 private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
190 String jsb = javaScriptBody(prefix, m, true);
194 StringBuilder argsCnt = new StringBuilder();
195 final String mn = findMethodName(m, argsCnt);
196 out.append(prefix).append(mn).append(" = function");
197 if (mn.equals("class__V")) {
198 toInitilize.add(accessClass(className(jc)) + "(false)." + mn);
202 for (int index = 0, i = 0; i < argsCnt.length(); i++) {
204 out.append("arg").append(String.valueOf(index));
206 final String desc = null;// XXX findDescriptor(args.get(i).getDescriptor());
207 if (argsCnt.charAt(i) == '1') {
213 out.append(") {").append("\n");
214 final byte[] code = m.getCode();
216 int len = m.getMaxLocals();
217 for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
219 out.append("arg").append(String.valueOf(i)).append(";\n");
221 out.append(" var s = new Array();\n");
224 out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n");
230 private String generateInstanceMethod(String prefix, MethodData m) throws IOException {
231 String jsb = javaScriptBody(prefix, m, false);
235 StringBuilder argsCnt = new StringBuilder();
236 final String mn = findMethodName(m, argsCnt);
237 out.append(prefix).append(mn).append(" = function");
240 for (int index = 1, i = 0; i < argsCnt.length(); i++) {
242 out.append("arg").append(String.valueOf(index));
243 if (argsCnt.charAt(i) == '1') {
249 out.append(") {").append("\n");
250 final byte[] code = m.getCode();
252 int len = m.getMaxLocals();
253 for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
255 out.append("arg").append(String.valueOf(i + 1)).append(";\n");
257 out.append(";\n var s = new Array();\n");
260 out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n");
266 private void produceCode(byte[] byteCodes) throws IOException {
267 out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
268 for (int i = 0; i < byteCodes.length; i++) {
270 out.append(" case " + i).append(": ");
271 final int c = readByte(byteCodes, i);
278 out.append("s.push(arg0);");
285 out.append("s.push(arg1);");
292 out.append("s.push(arg2);");
299 out.append("s.push(arg3);");
306 final int indx = readByte(byteCodes, ++i);
307 out.append("s.push(arg").append(indx + ");");
315 final int indx = readByte(byteCodes, ++i);
316 out.append("arg" + indx).append(" = s.pop();");
324 out.append("arg0 = s.pop();");
331 out.append("arg1 = s.pop();");
338 out.append("arg2 = s.pop();");
345 out.append("arg3 = s.pop();");
351 out.append("s.push(s.pop() + s.pop());");
357 out.append("{ var tmp = s.pop(); s.push(s.pop() - tmp); }");
363 out.append("s.push(s.pop() * s.pop());");
367 out.append("{ var tmp = s.pop(); s.push(Math.floor(s.pop() / tmp)); }");
371 out.append("{ var tmp = s.pop(); s.push(s.pop() / tmp); }");
377 out.append("{ var d = s.pop(); s.push(s.pop() % d); }");
381 out.append("s.push(s.pop() & s.pop());");
385 out.append("s.push(s.pop() | s.pop());");
389 out.append("s.push(s.pop() ^ s.pop());");
395 out.append("s.push(- s.pop());");
399 out.append("{ var v = s.pop(); s.push(s.pop() << v); }");
403 out.append("{ var v = s.pop(); s.push(s.pop() >> v); }");
407 out.append("{ var v = s.pop(); s.push(s.pop() >>> v); }");
410 final int varIndx = readByte(byteCodes, ++i);
411 final int incrBy = byteCodes[++i];
413 out.append("arg" + varIndx).append("++;");
415 out.append("arg" + varIndx).append(" += " + incrBy).append(";");
420 out.append("return;");
427 out.append("return s.pop();");
438 out.append("/* number conversion */");
444 out.append("s.push(Math.floor(s.pop()));");
449 out.append("/* number conversion */");
451 case opc_aconst_null:
452 out.append("s.push(null);");
455 out.append("s.push(-1);");
461 out.append("s.push(0);");
467 out.append("s.push(1);");
471 out.append("s.push(2);");
474 out.append("s.push(3);");
477 out.append("s.push(4);");
480 out.append("s.push(5);");
483 int indx = readByte(byteCodes, ++i);
484 String v = encodeConstant(indx);
485 out.append("s.push(").append(v).append(");");
490 int indx = readIntArg(byteCodes, i);
492 String v = encodeConstant(indx);
493 out.append("s.push(").append(v).append(");");
501 out.append("{ var delta = s.pop() - s.pop(); s.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }");
505 i = generateIf(byteCodes, i, "===");
508 i = generateIf(byteCodes, i, "!=");
510 case opc_if_icmpeq: {
511 i = generateIf(byteCodes, i, "==");
515 int indx = i + readIntArg(byteCodes, i);
516 out.append("if (s.pop() == 0) { gt = " + indx);
517 out.append("; continue; }");
522 int indx = i + readIntArg(byteCodes, i);
523 out.append("if (s.pop() != 0) { gt = " + indx);
524 out.append("; continue; }");
529 int indx = i + readIntArg(byteCodes, i);
530 out.append("if (s.pop() < 0) { gt = " + indx);
531 out.append("; continue; }");
536 int indx = i + readIntArg(byteCodes, i);
537 out.append("if (s.pop() <= 0) { gt = " + indx);
538 out.append("; continue; }");
543 int indx = i + readIntArg(byteCodes, i);
544 out.append("if (s.pop() > 0) { gt = " + indx);
545 out.append("; continue; }");
550 int indx = i + readIntArg(byteCodes, i);
551 out.append("if (s.pop() >= 0) { gt = " + indx);
552 out.append("; continue; }");
556 case opc_ifnonnull: {
557 int indx = i + readIntArg(byteCodes, i);
558 out.append("if (s.pop() !== null) { gt = " + indx);
559 out.append("; continue; }");
564 int indx = i + readIntArg(byteCodes, i);
565 out.append("if (s.pop() === null) { gt = " + indx);
566 out.append("; continue; }");
571 i = generateIf(byteCodes, i, "!=");
574 i = generateIf(byteCodes, i, ">");
577 i = generateIf(byteCodes, i, ">=");
580 i = generateIf(byteCodes, i, "<");
583 i = generateIf(byteCodes, i, "<=");
586 int indx = i + readIntArg(byteCodes, i);
587 out.append("gt = " + indx).append("; continue;");
591 case opc_lookupswitch: {
592 int table = i / 4 * 4 + 4;
593 int dflt = i + readInt4(byteCodes, table);
595 int n = readInt4(byteCodes, table);
597 out.append("switch (s.pop()) {\n");
599 int cnstnt = readInt4(byteCodes, table);
601 int offset = i + readInt4(byteCodes, table);
603 out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
605 out.append(" default: gt = " + dflt).append("; continue;\n}");
609 case opc_tableswitch: {
610 int table = i / 4 * 4 + 4;
611 int dflt = i + readInt4(byteCodes, table);
613 int low = readInt4(byteCodes, table);
615 int high = readInt4(byteCodes, table);
617 out.append("switch (s.pop()) {\n");
618 while (low <= high) {
619 int offset = i + readInt4(byteCodes, table);
621 out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
624 out.append(" default: gt = " + dflt).append("; continue;\n}");
628 case opc_invokeinterface: {
629 i = invokeVirtualMethod(byteCodes, i) + 2;
632 case opc_invokevirtual:
633 i = invokeVirtualMethod(byteCodes, i);
635 case opc_invokespecial:
636 i = invokeStaticMethod(byteCodes, i, false);
638 case opc_invokestatic:
639 i = invokeStaticMethod(byteCodes, i, true);
642 int indx = readIntArg(byteCodes, i);
643 String ci = jc.getClassName(indx);
644 out.append("s.push(new ");
645 out.append(accessClass(ci.replace('/','_')));
652 int type = byteCodes[i++];
653 out.append("s.push(new Array(s.pop()).fillNulls());");
656 case opc_anewarray: {
657 i += 2; // skip type of array
658 out.append("s.push(new Array(s.pop()).fillNulls());");
661 case opc_multianewarray: {
663 int dim = readByte(byteCodes, ++i);
664 out.append("{ var a0 = new Array(s.pop()).fillNulls();");
665 for (int d = 1; d < dim; d++) {
666 out.append("\n var l" + d).append(" = s.pop();");
667 out.append("\n for (var i" + d).append (" = 0; i" + d).
668 append(" < a" + (d - 1)).
669 append(".length; i" + d).append("++) {");
670 out.append("\n var a" + d).
671 append (" = new Array(l" + d).append(").fillNulls();");
672 out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d).
675 for (int d = 1; d < dim; d++) {
678 out.append("\ns.push(a0); }");
681 case opc_arraylength:
682 out.append("s.push(s.pop().length);");
692 out.append("{ var value = s.pop(); var indx = s.pop(); s.pop()[indx] = value; }");
703 out.append("{ var indx = s.pop(); s.push(s.pop()[indx]); }");
707 out.append("s.pop();");
709 out.append("s.pop();");
712 out.append("s.push(s[s.length - 1]);");
715 out.append("{ var v1 = s.pop(); var v2 = s.pop(); s.push(v1); s.push(v2); s.push(v1); }");
718 out.append("{ var v1 = s.pop(); var v2 = s.pop(); var v3 = s.pop(); s.push(v1); s.push(v3); s.push(v2); s.push(v1); }");
721 out.append("s.push(" + byteCodes[++i] + ");");
724 out.append("s.push(" + readIntArg(byteCodes, i) + ");");
728 int indx = readIntArg(byteCodes, i);
729 String[] fi = jc.getFieldInfoName(indx);
730 out.append("s.push(s.pop().fld_").
731 append(fi[1]).append(");");
735 case opc_getstatic: {
736 int indx = readIntArg(byteCodes, i);
737 String[] fi = jc.getFieldInfoName(indx);
738 out.append("s.push(").append(accessClass(fi[0].replace('/', '_')));
739 out.append('.').append(fi[1]).append(");");
744 case opc_putstatic: {
745 int indx = readIntArg(byteCodes, i);
746 String[] fi = jc.getFieldInfoName(indx);
747 out.append(accessClass(fi[0].replace('/', '_')));
748 out.append('.').append(fi[1]).append(" = s.pop();");
754 int indx = readIntArg(byteCodes, i);
755 String[] fi = jc.getFieldInfoName(indx);
756 out.append("{ var v = s.pop(); s.pop().fld_")
757 .append(fi[1]).append(" = v; }");
761 case opc_checkcast: {
762 int indx = readIntArg(byteCodes, i);
763 final String type = jc.getClassName(indx);
764 if (!type.startsWith("[")) {
765 // no way to check arrays right now
766 out.append("if(s[s.length - 1].$instOf_")
767 .append(type.replace('/', '_'))
768 .append(" != 1) throw {};"); // XXX proper exception
773 case opc_instanceof: {
774 int indx = readIntArg(byteCodes, i);
775 final String type = jc.getClassName(indx);
776 out.append("s.push(s.pop().$instOf_")
777 .append(type.replace('/', '_'))
778 .append(" ? 1 : 0);");
783 out.append("{ var t = s.pop(); s = new Array(1); s[0] = t; throw t; }");
787 out.append("throw 'unknown bytecode " + c + "';");
792 for (int j = prev; j <= i; j++) {
794 final int cc = readByte(byteCodes, j);
795 out.append(Integer.toString(cc));
802 private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
803 int indx = i + readIntArg(byteCodes, i);
804 out.append("if (s.pop() ").append(test).append(" s.pop()) { gt = " + indx);
805 out.append("; continue; }");
809 private int readIntArg(byte[] byteCodes, int offsetInstruction) {
810 final int indxHi = byteCodes[offsetInstruction + 1] << 8;
811 final int indxLo = byteCodes[offsetInstruction + 2];
812 return (indxHi & 0xffffff00) | (indxLo & 0xff);
814 private int readInt4(byte[] byteCodes, int offsetInstruction) {
815 final int d = byteCodes[offsetInstruction + 0] << 24;
816 final int c = byteCodes[offsetInstruction + 1] << 16;
817 final int b = byteCodes[offsetInstruction + 2] << 8;
818 final int a = byteCodes[offsetInstruction + 3];
819 return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
821 private int readByte(byte[] byteCodes, int offsetInstruction) {
822 return (byteCodes[offsetInstruction] + 256) % 256;
825 private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) {
827 Boolean count = null;
828 boolean array = false;
830 int firstPos = sig.length();
831 while (i < descriptor.length()) {
832 char ch = descriptor.charAt(i++);
853 if (ch == 'J' || ch == 'D') {
859 hasReturnType[0] = true;
860 sig.insert(firstPos, ch);
862 sig.insert(firstPos, "_3");
869 hasReturnType[0] = false;
870 sig.insert(firstPos, 'V');
873 int next = descriptor.indexOf(';', i);
874 String realSig = mangleSig(descriptor, i - 1, next + 1);
882 sig.insert(firstPos, realSig);
884 sig.insert(firstPos, "_3");
886 hasReturnType[0] = true;
894 throw new IllegalStateException("Invalid char: " + ch);
899 private static String mangleSig(String txt, int first, int last) {
900 StringBuilder sb = new StringBuilder();
901 for (int i = first; i < last; i++) {
902 final char ch = txt.charAt(i);
904 case '/': sb.append('_'); break;
905 case '_': sb.append("_1"); break;
906 case ';': sb.append("_2"); break;
907 case '[': sb.append("_3"); break;
908 default: sb.append(ch); break;
911 return sb.toString();
914 private static String findMethodName(MethodData m, StringBuilder cnt) {
915 StringBuilder name = new StringBuilder();
916 if ("<init>".equals(m.getName())) { // NOI18N
917 name.append("cons"); // NOI18N
918 } else if ("<clinit>".equals(m.getName())) { // NOI18N
919 name.append("class"); // NOI18N
921 name.append(m.getName());
924 boolean hasReturn[] = { false };
925 countArgs(m.getInternalSig(), hasReturn, name, cnt);
926 return name.toString();
929 static String findMethodName(String[] mi, StringBuilder cnt, boolean[] hasReturn) {
930 StringBuilder name = new StringBuilder();
931 String descr = mi[2];//mi.getDescriptor();
933 if ("<init>".equals(nm)) { // NOI18N
934 name.append("cons"); // NOI18N
938 countArgs(descr, hasReturn, name, cnt);
939 return name.toString();
942 private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
944 int methodIndex = readIntArg(byteCodes, i);
945 String[] mi = jc.getFieldInfoName(methodIndex);
946 boolean[] hasReturn = { false };
947 StringBuilder cnt = new StringBuilder();
948 String mn = findMethodName(mi, cnt, hasReturn);
950 for (int j = cnt.length() - 1; j >= 0; j--) {
951 out.append("var v" + j).append(" = s.pop(); ");
955 out.append("s.push(");
957 final String in = mi[0];
958 out.append(accessClass(in.replace('/', '_')));
959 out.append("(false).");
964 out.append("s.pop()");
967 for (int j = 0; j < cnt.length(); j++) {
981 private int invokeVirtualMethod(byte[] byteCodes, int i)
983 int methodIndex = readIntArg(byteCodes, i);
984 String[] mi = jc.getFieldInfoName(methodIndex);
985 boolean[] hasReturn = { false };
986 StringBuilder cnt = new StringBuilder();
987 String mn = findMethodName(mi, cnt, hasReturn);
989 for (int j = cnt.length() - 1; j >= 0; j--) {
990 out.append("var v" + j).append(" = s.pop(); ");
992 out.append("var self = s.pop(); ");
994 out.append("s.push(");
1000 for (int j = 0; j < cnt.length(); j++) {
1002 out.append("v" + j);
1013 private void addReference(String cn) throws IOException {
1014 if (requireReference(cn)) {
1015 out.append(" /* needs ").append(cn).append(" */");
1019 private void outType(String d, StringBuilder out) {
1021 while (d.charAt(0) == '[') {
1025 if (d.charAt(0) == 'L') {
1026 assert d.charAt(d.length() - 1) == ';';
1027 out.append(d.replace('/', '_').substring(0, d.length() - 1));
1033 private String encodeConstant(int entryIndex) throws IOException {
1034 String[] classRef = { null };
1035 String s = jc.stringValue(entryIndex, classRef);
1036 if (classRef[0] != null) {
1037 addReference(classRef[0]);
1038 s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
1043 private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
1044 byte[] arr = m.findAnnotationData(true);
1048 final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
1049 class P extends AnnotationParser {
1055 String[] args = new String[30];
1059 protected void visitAttr(String type, String attr, String at, String value) {
1060 if (type.equals(jvmType)) {
1061 if ("body".equals(attr)) {
1063 } else if ("args".equals(attr)) {
1064 args[cnt++] = value;
1066 throw new IllegalArgumentException(attr);
1073 if (p.body == null) {
1076 StringBuilder cnt = new StringBuilder();
1077 final String mn = findMethodName(m, cnt);
1078 out.append(prefix).append(mn);
1079 out.append(" = function(");
1083 out.append(p.args[0]);
1090 for (int i = 0; i < cnt.length(); i++) {
1092 out.append(p.args[index]);
1096 out.append(") {").append("\n");
1098 out.append("\n}\n");
1101 private static String className(ClassData jc) {
1102 //return jc.getName().getInternalName().replace('/', '_');
1103 return jc.getClassName().replace('/', '_');
1106 private static String[] findAnnotation(
1107 byte[] arr, ClassData cd, final String className,
1108 final String... attrNames
1109 ) throws IOException {
1113 final String[] values = new String[attrNames.length];
1114 final boolean[] found = { false };
1115 final String jvmType = "L" + className.replace('.', '/') + ";";
1116 AnnotationParser ap = new AnnotationParser(false) {
1118 protected void visitAttr(String type, String attr, String at, String value) {
1119 if (type.equals(jvmType)) {
1121 for (int i = 0; i < attrNames.length; i++) {
1122 if (attrNames[i].equals(attr)) {
1131 return found[0] ? values : null;
1134 private CharSequence initField(FieldData v) {
1135 final String is = v.getInternalSig();
1136 if (is.length() == 1) {
1137 switch (is.charAt(0)) {
1143 case 'I': return " = 0;";
1145 case 'D': return " = 0.0;";
1147 throw new IllegalStateException(is);
1153 private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
1154 AnnotationParser ap = new AnnotationParser(true) {
1159 protected void visitAnnotationStart(String type) throws IOException {
1163 out.append('"').append(type).append("\" : {\n");
1168 protected void visitAnnotationEnd(String type) throws IOException {
1169 out.append("\n}\n");
1173 protected void visitAttr(String type, String attr, String attrType, String value)
1174 throws IOException {
1181 out.append(attr).append("__").append(attrType).append(" : ").append(value);