77import java .util .ArrayList ;
88import java .util .Collections ;
99import java .util .List ;
10+ import java .util .Map ;
11+ import java .util .Map .Entry ;
1012
1113import org .objectweb .asm .AnnotationVisitor ;
1214import org .objectweb .asm .ClassWriter ;
1315import org .objectweb .asm .FieldVisitor ;
1416import org .objectweb .asm .MethodVisitor ;
1517import org .objectweb .asm .Opcodes ;
18+ import org .objectweb .asm .Type ;
1619
1720import org .python .core .imp ;
21+ import org .python .compiler .ProxyCodeHelpers .AnnotationDescr ;
1822
1923public class ClassFile
2024{
@@ -27,6 +31,7 @@ public class ClassFile
2731 String [] interfaces ;
2832 List <MethodVisitor > methodVisitors ;
2933 List <FieldVisitor > fieldVisitors ;
34+ List <AnnotationVisitor > annotationVisitors ;
3035
3136 public static String fixName (String n ) {
3237 if (n .indexOf ('.' ) == -1 )
@@ -37,6 +42,34 @@ public static String fixName(String n) {
3742 }
3843 return new String (c );
3944 }
45+
46+
47+ public static void visitAnnotations (AnnotationVisitor av , Map <String , Object > fields ) {
48+ for (Entry <String , Object >field : fields .entrySet ()) {
49+ visitAnnotation (av , field .getKey (), field .getValue ());
50+ }
51+ }
52+
53+ // See org.objectweb.asm.AnnotationVisitor for details
54+ // TODO Support annotation annotations and annotation array annotations
55+ public static void visitAnnotation (AnnotationVisitor av , String fieldName , Object fieldValue ) {
56+ Class <?> fieldValueClass = fieldValue .getClass ();
57+
58+ if (fieldValue instanceof Class ) {
59+ av .visit (fieldName , Type .getType ((Class <?>)fieldValue ));
60+ } else if (fieldValueClass .isEnum ()) {
61+ av .visitEnum (fieldName , ProxyCodeHelpers .mapType (fieldValueClass ), fieldValue .toString ());
62+ } else if (fieldValue instanceof List ) {
63+ AnnotationVisitor arrayVisitor = av .visitArray (fieldName );
64+ List <Object > fieldList = (List <Object >)fieldValue ;
65+ for (Object arrayField : fieldList ) {
66+ visitAnnotation (arrayVisitor , null , arrayField );
67+ }
68+ arrayVisitor .visitEnd ();
69+ } else {
70+ av .visit (fieldName , fieldValue );
71+ }
72+ }
4073
4174 public ClassFile (String name ) {
4275 this (name , "java/lang/Object" , Opcodes .ACC_SYNCHRONIZED | Opcodes .ACC_PUBLIC ,
@@ -56,6 +89,7 @@ public ClassFile(String name, String superclass, int access, long mtime) {
5689 cw = new ClassWriter (ClassWriter .COMPUTE_FRAMES );
5790 methodVisitors = Collections .synchronizedList (new ArrayList <MethodVisitor >());
5891 fieldVisitors = Collections .synchronizedList (new ArrayList <FieldVisitor >());
92+ annotationVisitors = Collections .synchronizedList (new ArrayList <AnnotationVisitor >());
5993 }
6094
6195 public void setSource (String name ) {
@@ -77,7 +111,54 @@ public Code addMethod(String name, String type, int access)
77111 methodVisitors .add (pmv );
78112 return pmv ;
79113 }
80-
114+ public Code addMethod (String name , String type , int access , String [] exceptions )
115+ throws IOException
116+ {
117+ MethodVisitor mv = cw .visitMethod (access , name , type , null , exceptions );
118+ Code pmv = new Code (mv , type , access );
119+ methodVisitors .add (pmv );
120+ return pmv ;
121+ }
122+
123+ public Code addMethod (String name , String type , int access , String [] exceptions ,
124+ AnnotationDescr []methodAnnotationDescrs , AnnotationDescr [][] parameterAnnotationDescrs )
125+ throws IOException
126+ {
127+ MethodVisitor mv = cw .visitMethod (access , name , type , null , exceptions );
128+
129+ // method annotations
130+ for (AnnotationDescr ad : methodAnnotationDescrs ) {
131+ AnnotationVisitor av = mv .visitAnnotation (ad .getName (), true );
132+ if (ad .hasFields ()) {
133+ visitAnnotations (av , ad .getFields ());
134+ }
135+ av .visitEnd ();
136+ }
137+
138+ // parameter annotations
139+ for (int i = 0 ; i < parameterAnnotationDescrs .length ; i ++) {
140+ for (AnnotationDescr ad : parameterAnnotationDescrs [i ]) {
141+ AnnotationVisitor av = mv .visitParameterAnnotation (i , ad .getName (), true );
142+ if (ad .hasFields ()) {
143+ visitAnnotations (av , ad .getFields ());
144+ }
145+ av .visitEnd ();
146+ }
147+ }
148+
149+ Code pmv = new Code (mv , type , access );
150+ methodVisitors .add (pmv );
151+ return pmv ;
152+ }
153+
154+ public void addClassAnnotation (AnnotationDescr annotationDescr ) {
155+ AnnotationVisitor av = cw .visitAnnotation (annotationDescr .getName (), true );
156+ if (annotationDescr .hasFields ()) {
157+ visitAnnotations (av , annotationDescr .getFields ());
158+ }
159+ annotationVisitors .add (av );
160+ }
161+
81162 public void addField (String name , String type , int access )
82163 throws IOException
83164 {
@@ -103,6 +184,12 @@ public void endMethods()
103184 }
104185 }
105186
187+ public void endClassAnnotations () {
188+ for (AnnotationVisitor av : annotationVisitors ) {
189+ av .visitEnd ();
190+ }
191+ }
192+
106193 public void write (OutputStream stream ) throws IOException {
107194 cw .visit (Opcodes .V1_5 , Opcodes .ACC_PUBLIC + Opcodes .ACC_SUPER , this .name , null , this .superclass , interfaces );
108195 AnnotationVisitor av = cw .visitAnnotation ("Lorg/python/compiler/APIVersion;" , true );
@@ -118,6 +205,7 @@ public void write(OutputStream stream) throws IOException {
118205 if (sfilename != null ) {
119206 cw .visitSource (sfilename , null );
120207 }
208+ endClassAnnotations ();
121209 endFields ();
122210 endMethods ();
123211
@@ -129,4 +217,5 @@ public void write(OutputStream stream) throws IOException {
129217 //debug(baos);
130218 baos .close ();
131219 }
220+
132221}
0 commit comments