KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > classfmt > AnnotationInfo


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 BEA Systems, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * tyeung@bea.com - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.classfmt;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.Annotation;
15 import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
16 import org.eclipse.jdt.internal.compiler.env.*;
17 import org.eclipse.jdt.internal.compiler.impl.*;
18 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
19
20 public class AnnotationInfo extends ClassFileStruct implements IBinaryAnnotation {
21     /** The name of the annotation type */
22     private char[] typename;
23     /**
24      * null until this annotation is initialized
25      * @see #getElementValuePairs()
26      */

27     private ElementValuePairInfo[] pairs;
28
29     long standardAnnotationTagBits = 0;
30     int readOffset = 0;
31
32     static Object JavaDoc[] EmptyValueArray = new Object JavaDoc[0];
33
34 AnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset) {
35     super(classFileBytes, contantPoolOffsets, offset);
36 }
37 /**
38  * @param classFileBytes
39  * @param offset the offset into <code>classFileBytes</code> for the "type_index" of the annotation attribute.
40  * @param populate <code>true</code> to indicate to build out the annotation structure.
41  */

42 AnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset, boolean runtimeVisible, boolean populate) {
43     this(classFileBytes, contantPoolOffsets, offset);
44     if (populate)
45         decodeAnnotation();
46     else
47         this.readOffset = scanAnnotation(0, runtimeVisible, true);
48 }
49 private void decodeAnnotation() {
50     this.readOffset = 0;
51     int utf8Offset = this.constantPoolOffsets[u2At(0)] - structOffset;
52     this.typename = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
53     int numberOfPairs = u2At(2);
54     // u2 type_index + u2 num_member_value_pair
55
this.readOffset += 4;
56     this.pairs = numberOfPairs == 0 ? ElementValuePairInfo.NoMembers : new ElementValuePairInfo[numberOfPairs];
57     for (int i = 0; i < numberOfPairs; i++) {
58         // u2 member_name_index;
59
utf8Offset = this.constantPoolOffsets[u2At(this.readOffset)] - structOffset;
60         char[] membername = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
61         this.readOffset += 2;
62         Object JavaDoc value = decodeDefaultValue();
63         this.pairs[i] = new ElementValuePairInfo(membername, value);
64     }
65 }
66 Object JavaDoc decodeDefaultValue() {
67     Object JavaDoc value = null;
68     // u1 tag;
69
int tag = u1At(this.readOffset);
70     this.readOffset++;
71     int constValueOffset = -1;
72     switch (tag) {
73         case 'Z': // boolean constant
74
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
75             value = BooleanConstant.fromValue(i4At(constValueOffset + 1) == 1);
76             this.readOffset += 2;
77             break;
78         case 'I': // integer constant
79
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
80             value = IntConstant.fromValue(i4At(constValueOffset + 1));
81             this.readOffset += 2;
82             break;
83         case 'C': // char constant
84
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
85             value = CharConstant.fromValue((char) i4At(constValueOffset + 1));
86             this.readOffset += 2;
87             break;
88         case 'B': // byte constant
89
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
90             value = ByteConstant.fromValue((byte) i4At(constValueOffset + 1));
91             this.readOffset += 2;
92             break;
93         case 'S': // short constant
94
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
95             value = ShortConstant.fromValue((short) i4At(constValueOffset + 1));
96             this.readOffset += 2;
97             break;
98         case 'D': // double constant
99
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
100             value = DoubleConstant.fromValue(doubleAt(constValueOffset + 1));
101             this.readOffset += 2;
102             break;
103         case 'F': // float constant
104
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
105             value = FloatConstant.fromValue(floatAt(constValueOffset + 1));
106             this.readOffset += 2;
107             break;
108         case 'J': // long constant
109
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
110             value = LongConstant.fromValue(i8At(constValueOffset + 1));
111             this.readOffset += 2;
112             break;
113         case 's': // String
114
constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
115             value = StringConstant.fromValue(String.valueOf(utf8At(constValueOffset + 3, u2At(constValueOffset + 1))));
116             this.readOffset += 2;
117             break;
118         case 'e':
119             constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
120             char[] typeName = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
121             this.readOffset += 2;
122             constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
123             char[] constName = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
124             this.readOffset += 2;
125             value = new EnumConstantSignature(typeName, constName);
126             break;
127         case 'c':
128             constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
129             char[] className = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
130             value = new ClassSignature(className);
131             this.readOffset += 2;
132             break;
133         case '@':
134             value = new AnnotationInfo(this.reference, this.constantPoolOffsets, this.readOffset + this.structOffset, false, true);
135             this.readOffset += ((AnnotationInfo) value).readOffset;
136             break;
137         case '[':
138             int numberOfValues = u2At(this.readOffset);
139             this.readOffset += 2;
140             if (numberOfValues == 0) {
141                 value = EmptyValueArray;
142             } else {
143                 Object JavaDoc[] arrayElements = new Object JavaDoc[numberOfValues];
144                 value = arrayElements;
145                 for (int i = 0; i < numberOfValues; i++)
146                     arrayElements[i] = decodeDefaultValue();
147             }
148             break;
149         default:
150             throw new IllegalStateException JavaDoc("Unrecognized tag " + (char) tag); //$NON-NLS-1$
151
}
152     return value;
153 }
154 public IBinaryElementValuePair[] getElementValuePairs() {
155     if (this.pairs == null)
156         initialize();
157     return this.pairs;
158 }
159 public char[] getTypeName() {
160     return this.typename;
161 }
162 void initialize() {
163     if (this.pairs == null)
164         decodeAnnotation();
165 }
166 private int readRetentionPolicy(int offset) {
167     int currentOffset = offset;
168     int tag = u1At(currentOffset);
169     currentOffset++;
170     switch (tag) {
171         case 'e':
172             int utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - structOffset;
173             char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
174             currentOffset += 2;
175             if (typeName.length == 38 && CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_RETENTIONPOLICY)) {
176                 utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - structOffset;
177                 char[] constName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
178                 this.standardAnnotationTagBits |= Annotation.getRetentionPolicy(constName);
179             }
180             currentOffset += 2;
181             break;
182         case 'B':
183         case 'C':
184         case 'D':
185         case 'F':
186         case 'I':
187         case 'J':
188         case 'S':
189         case 'Z':
190         case 's':
191         case 'c':
192             currentOffset += 2;
193             break;
194         case '@':
195             // none of the supported standard annotation are in the nested
196
// level.
197
currentOffset = scanAnnotation(currentOffset, false, false);
198             break;
199         case '[':
200             int numberOfValues = u2At(currentOffset);
201             currentOffset += 2;
202             for (int i = 0; i < numberOfValues; i++)
203                 currentOffset = scanElementValue(currentOffset);
204             break;
205         default:
206             throw new IllegalStateException JavaDoc();
207     }
208     return currentOffset;
209 }
210 private int readTargetValue(int offset) {
211     int currentOffset = offset;
212     int tag = u1At(currentOffset);
213     currentOffset++;
214     switch (tag) {
215         case 'e':
216             int utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - structOffset;
217             char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
218             currentOffset += 2;
219             if (typeName.length == 34 && CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_ELEMENTTYPE)) {
220                 utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - structOffset;
221                 char[] constName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
222                 this.standardAnnotationTagBits |= Annotation.getTargetElementType(constName);
223             }
224             currentOffset += 2;
225             break;
226         case 'B':
227         case 'C':
228         case 'D':
229         case 'F':
230         case 'I':
231         case 'J':
232         case 'S':
233         case 'Z':
234         case 's':
235         case 'c':
236             currentOffset += 2;
237             break;
238         case '@':
239             // none of the supported standard annotation are in the nested
240
// level.
241
currentOffset = scanAnnotation(currentOffset, false, false);
242             break;
243         case '[':
244             int numberOfValues = u2At(currentOffset);
245             currentOffset += 2;
246             if (numberOfValues == 0) {
247                 this.standardAnnotationTagBits |= TagBits.AnnotationTarget;
248             } else {
249                 for (int i = 0; i < numberOfValues; i++)
250                     currentOffset = readTargetValue(currentOffset);
251             }
252             break;
253         default:
254             throw new IllegalStateException JavaDoc();
255     }
256     return currentOffset;
257 }
258 /**
259  * Read through this annotation in order to figure out the necessary tag
260  * bits and the length of this annotation. The data structure will not be
261  * flushed out.
262  *
263  * The tag bits are derived from the following (supported) standard
264  * annotation. java.lang.annotation.Documented,
265  * java.lang.annotation.Retention, java.lang.annotation.Target, and
266  * java.lang.Deprecated
267  *
268  * @param expectRuntimeVisibleAnno
269  * <code>true</cod> to indicate that this is a runtime-visible annotation
270  * @param toplevel <code>false</code> to indicate that an nested annotation is read.
271  * <code>true</code> otherwise
272  * @return the next offset to read.
273  */

274 private int scanAnnotation(int offset, boolean expectRuntimeVisibleAnno, boolean toplevel) {
275     int currentOffset = offset;
276     int utf8Offset = this.constantPoolOffsets[u2At(offset)] - structOffset;
277     char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
278     if (toplevel)
279         this.typename = typeName;
280     int numberOfPairs = u2At(offset + 2);
281     // u2 type_index + u2 number_member_value_pair
282
currentOffset += 4;
283     if (expectRuntimeVisibleAnno && toplevel) {
284         switch (typeName.length) {
285             case 22:
286                 if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_DEPRECATED)) {
287                     this.standardAnnotationTagBits |= TagBits.AnnotationDeprecated;
288                     return currentOffset;
289                 }
290                 break;
291             case 29:
292                 if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_TARGET)) {
293                     currentOffset += 2;
294                     return readTargetValue(currentOffset);
295                 }
296                 break;
297             case 33:
298                 if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_DOCUMENTED)) {
299                     this.standardAnnotationTagBits |= TagBits.AnnotationDocumented;
300                     return currentOffset;
301                 }
302                 break;
303             case 32:
304                 if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_RETENTION)) {
305                     currentOffset += 2;
306                     return readRetentionPolicy(currentOffset);
307                 }
308                 if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_INHERITED)) {
309                     this.standardAnnotationTagBits |= TagBits.AnnotationInherited;
310                     return currentOffset;
311                 }
312                 break;
313         }
314     }
315     for (int i = 0; i < numberOfPairs; i++) {
316         // u2 member_name_index
317
currentOffset += 2;
318         currentOffset = scanElementValue(currentOffset);
319     }
320     return currentOffset;
321 }
322 /**
323  * @param offset
324  * the offset to start reading.
325  * @return the next offset to read.
326  */

327 private int scanElementValue(int offset) {
328     int currentOffset = offset;
329     int tag = u1At(currentOffset);
330     currentOffset++;
331     switch (tag) {
332         case 'B':
333         case 'C':
334         case 'D':
335         case 'F':
336         case 'I':
337         case 'J':
338         case 'S':
339         case 'Z':
340         case 's':
341         case 'c':
342             currentOffset += 2;
343             break;
344         case 'e':
345             currentOffset += 4;
346             break;
347         case '@':
348             // none of the supported standard annotation are in the nested
349
// level.
350
currentOffset = scanAnnotation(currentOffset, false, false);
351             break;
352         case '[':
353             int numberOfValues = u2At(currentOffset);
354             currentOffset += 2;
355             for (int i = 0; i < numberOfValues; i++)
356                 currentOffset = scanElementValue(currentOffset);
357             break;
358         default:
359             throw new IllegalStateException JavaDoc();
360     }
361     return currentOffset;
362 }
363 public String JavaDoc toString() {
364     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
365     buffer.append('@');
366     buffer.append(this.typename);
367     if (this.pairs != null) {
368         buffer.append('(');
369         buffer.append("\n\t"); //$NON-NLS-1$
370
for (int i = 0, len = this.pairs.length; i < len; i++) {
371             if (i > 0)
372                 buffer.append(",\n\t"); //$NON-NLS-1$
373
buffer.append(this.pairs[i]);
374         }
375         buffer.append(')');
376     }
377     return buffer.toString();
378 }
379 }
380
Popular Tags