52 /**
53 * Parses the annotations described by the specified byte array.
54 * resolving constant references in the specified constant pool.
55 * The array must contain an array of annotations as described
56 * in the RuntimeVisibleAnnotations_attribute:
57 *
58 * u2 num_annotations;
59 * annotation annotations[num_annotations];
60 *
61 * @throws AnnotationFormatError if an annotation is found to be
62 * malformed.
63 */
64 public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
65 byte[] rawAnnotations,
66 ConstantPool constPool,
67 Class<?> container) {
68 if (rawAnnotations == null)
69 return Collections.emptyMap();
70
71 try {
72 return parseAnnotations2(rawAnnotations, constPool, container);
73 } catch(BufferUnderflowException e) {
74 throw new AnnotationFormatError("Unexpected end of annotations.");
75 } catch(IllegalArgumentException e) {
76 // Type mismatch in constant pool
77 throw new AnnotationFormatError(e);
78 }
79 }
80
81 private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
82 byte[] rawAnnotations,
83 ConstantPool constPool,
84 Class<?> container) {
85 Map<Class<? extends Annotation>, Annotation> result =
86 new LinkedHashMap<Class<? extends Annotation>, Annotation>();
87 ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
88 int numAnnotations = buf.getShort() & 0xFFFF;
89 for (int i = 0; i < numAnnotations; i++) {
90 Annotation a = parseAnnotation(buf, constPool, container, false);
91 if (a != null) {
92 Class<? extends Annotation> klass = a.annotationType();
93 AnnotationType type = AnnotationType.getInstance(klass);
94 if (type.retention() == RetentionPolicy.RUNTIME)
95 if (result.put(klass, a) != null)
96 throw new AnnotationFormatError(
97 "Duplicate annotation for class: "+klass+": " + a);
98 }
99 }
100 return result;
101 }
102
103 /**
104 * Parses the parameter annotations described by the specified byte array.
105 * resolving constant references in the specified constant pool.
106 * The array must contain an array of annotations as described
107 * in the RuntimeVisibleParameterAnnotations_attribute:
108 *
109 * u1 num_parameters;
110 * {
111 * u2 num_annotations;
112 * annotation annotations[num_annotations];
113 * } parameter_annotations[num_parameters];
114 *
115 * Unlike parseAnnotations, rawAnnotations must not be null!
116 * A null value must be handled by the caller. This is so because
117 * we cannot determine the number of parameters if rawAnnotations
118 * is null. Also, the caller should check that the number
119 * of parameters indicated by the return value of this method
172 * byte buffer, resolving constant references in the specified constant
173 * pool. The cursor of the byte buffer must point to an "annotation
174 * structure" as described in the RuntimeVisibleAnnotations_attribute:
175 *
176 * annotation {
177 * u2 type_index;
178 * u2 num_member_value_pairs;
179 * { u2 member_name_index;
180 * member_value value;
181 * } member_value_pairs[num_member_value_pairs];
182 * }
183 * }
184 *
185 * Returns the annotation, or null if the annotation's type cannot
186 * be found by the VM, or is not a valid annotation type.
187 *
188 * @param exceptionOnMissingAnnotationClass if true, throw
189 * TypeNotPresentException if a referenced annotation type is not
190 * available at runtime
191 */
192 @SuppressWarnings("unchecked")
193 static Annotation parseAnnotation(ByteBuffer buf,
194 ConstantPool constPool,
195 Class<?> container,
196 boolean exceptionOnMissingAnnotationClass) {
197 int typeIndex = buf.getShort() & 0xFFFF;
198 Class<? extends Annotation> annotationClass = null;
199 String sig = "[unknown]";
200 try {
201 try {
202 sig = constPool.getUTF8At(typeIndex);
203 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
204 } catch (IllegalArgumentException ex) {
205 // support obsolete early jsr175 format class files
206 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
207 }
208 } catch (NoClassDefFoundError e) {
209 if (exceptionOnMissingAnnotationClass)
210 // note: at this point sig is "[unknown]" or VM-style
211 // name instead of a binary name
212 throw new TypeNotPresentException(sig, e);
213 skipAnnotation(buf, false);
214 return null;
215 }
216 catch (TypeNotPresentException e) {
217 if (exceptionOnMissingAnnotationClass)
218 throw e;
219 skipAnnotation(buf, false);
220 return null;
221 }
222 AnnotationType type = null;
223 try {
224 type = AnnotationType.getInstance(annotationClass);
225 } catch (IllegalArgumentException e) {
226 skipAnnotation(buf, false);
227 return null;
228 }
229
230 Map<String, Class<?>> memberTypes = type.memberTypes();
231 Map<String, Object> memberValues =
232 new LinkedHashMap<String, Object>(type.memberDefaults());
233
234 int numMembers = buf.getShort() & 0xFFFF;
235 for (int i = 0; i < numMembers; i++) {
236 int memberNameIndex = buf.getShort() & 0xFFFF;
237 String memberName = constPool.getUTF8At(memberNameIndex);
238 Class<?> memberType = memberTypes.get(memberName);
239
240 if (memberType == null) {
241 // Member is no longer present in annotation type; ignore it
781 skipAnnotation(buf, true);
782 break;
783 case '[':
784 skipArray(buf);
785 break;
786 default:
787 // Class, primitive, or String
788 buf.getShort();
789 }
790 }
791
792 /**
793 * Skips the array value at the current position in the specified byte
794 * buffer. The cursor of the byte buffer must point to an array value
795 * struct.
796 */
797 private static void skipArray(ByteBuffer buf) {
798 int length = buf.getShort() & 0xFFFF;
799 for (int i = 0; i < length; i++)
800 skipMemberValue(buf);
801 }
802
803 /*
804 * This method converts the annotation map returned by the parseAnnotations()
805 * method to an array. It is called by Field.getDeclaredAnnotations(),
806 * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
807 * This avoids the reflection classes to load the Annotation class until
808 * it is needed.
809 */
810 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
811 public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
812 return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
813 }
814
815 static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
816 }
|
52 /**
53 * Parses the annotations described by the specified byte array.
54 * resolving constant references in the specified constant pool.
55 * The array must contain an array of annotations as described
56 * in the RuntimeVisibleAnnotations_attribute:
57 *
58 * u2 num_annotations;
59 * annotation annotations[num_annotations];
60 *
61 * @throws AnnotationFormatError if an annotation is found to be
62 * malformed.
63 */
64 public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
65 byte[] rawAnnotations,
66 ConstantPool constPool,
67 Class<?> container) {
68 if (rawAnnotations == null)
69 return Collections.emptyMap();
70
71 try {
72 return parseAnnotations2(rawAnnotations, constPool, container, null);
73 } catch(BufferUnderflowException e) {
74 throw new AnnotationFormatError("Unexpected end of annotations.");
75 } catch(IllegalArgumentException e) {
76 // Type mismatch in constant pool
77 throw new AnnotationFormatError(e);
78 }
79 }
80
81 /**
82 * Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
83 * with an additional parameter {@code selectAnnotationClasses} which selects the
84 * annotation types to parse (other than selected are quickly skipped).<p>
85 * This method is only used to parse select meta annotations in the construction
86 * phase of {@link AnnotationType} instances to prevent infinite recursion.
87 *
88 * @param selectAnnotationClasses an array of annotation types to select when parsing
89 */
90 @SafeVarargs
91 static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
92 byte[] rawAnnotations,
93 ConstantPool constPool,
94 Class<?> container,
95 Class<? extends Annotation> ... selectAnnotationClasses) {
96 if (rawAnnotations == null)
97 return Collections.emptyMap();
98
99 try {
100 return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
101 } catch(BufferUnderflowException e) {
102 throw new AnnotationFormatError("Unexpected end of annotations.");
103 } catch(IllegalArgumentException e) {
104 // Type mismatch in constant pool
105 throw new AnnotationFormatError(e);
106 }
107 }
108
109 private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
110 byte[] rawAnnotations,
111 ConstantPool constPool,
112 Class<?> container,
113 Class<? extends Annotation>[] selectAnnotationClasses) {
114 Map<Class<? extends Annotation>, Annotation> result =
115 new LinkedHashMap<Class<? extends Annotation>, Annotation>();
116 ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
117 int numAnnotations = buf.getShort() & 0xFFFF;
118 for (int i = 0; i < numAnnotations; i++) {
119 Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
120 if (a != null) {
121 Class<? extends Annotation> klass = a.annotationType();
122 if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
123 result.put(klass, a) != null) {
124 throw new AnnotationFormatError(
125 "Duplicate annotation for class: "+klass+": " + a);
126 }
127 }
128 }
129 return result;
130 }
131
132 /**
133 * Parses the parameter annotations described by the specified byte array.
134 * resolving constant references in the specified constant pool.
135 * The array must contain an array of annotations as described
136 * in the RuntimeVisibleParameterAnnotations_attribute:
137 *
138 * u1 num_parameters;
139 * {
140 * u2 num_annotations;
141 * annotation annotations[num_annotations];
142 * } parameter_annotations[num_parameters];
143 *
144 * Unlike parseAnnotations, rawAnnotations must not be null!
145 * A null value must be handled by the caller. This is so because
146 * we cannot determine the number of parameters if rawAnnotations
147 * is null. Also, the caller should check that the number
148 * of parameters indicated by the return value of this method
201 * byte buffer, resolving constant references in the specified constant
202 * pool. The cursor of the byte buffer must point to an "annotation
203 * structure" as described in the RuntimeVisibleAnnotations_attribute:
204 *
205 * annotation {
206 * u2 type_index;
207 * u2 num_member_value_pairs;
208 * { u2 member_name_index;
209 * member_value value;
210 * } member_value_pairs[num_member_value_pairs];
211 * }
212 * }
213 *
214 * Returns the annotation, or null if the annotation's type cannot
215 * be found by the VM, or is not a valid annotation type.
216 *
217 * @param exceptionOnMissingAnnotationClass if true, throw
218 * TypeNotPresentException if a referenced annotation type is not
219 * available at runtime
220 */
221 static Annotation parseAnnotation(ByteBuffer buf,
222 ConstantPool constPool,
223 Class<?> container,
224 boolean exceptionOnMissingAnnotationClass) {
225 return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
226 }
227
228 @SuppressWarnings("unchecked")
229 private static Annotation parseAnnotation2(ByteBuffer buf,
230 ConstantPool constPool,
231 Class<?> container,
232 boolean exceptionOnMissingAnnotationClass,
233 Class<? extends Annotation>[] selectAnnotationClasses) {
234 int typeIndex = buf.getShort() & 0xFFFF;
235 Class<? extends Annotation> annotationClass = null;
236 String sig = "[unknown]";
237 try {
238 try {
239 sig = constPool.getUTF8At(typeIndex);
240 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
241 } catch (IllegalArgumentException ex) {
242 // support obsolete early jsr175 format class files
243 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
244 }
245 } catch (NoClassDefFoundError e) {
246 if (exceptionOnMissingAnnotationClass)
247 // note: at this point sig is "[unknown]" or VM-style
248 // name instead of a binary name
249 throw new TypeNotPresentException(sig, e);
250 skipAnnotation(buf, false);
251 return null;
252 }
253 catch (TypeNotPresentException e) {
254 if (exceptionOnMissingAnnotationClass)
255 throw e;
256 skipAnnotation(buf, false);
257 return null;
258 }
259 if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
260 skipAnnotation(buf, false);
261 return null;
262 }
263 AnnotationType type = null;
264 try {
265 type = AnnotationType.getInstance(annotationClass);
266 } catch (IllegalArgumentException e) {
267 skipAnnotation(buf, false);
268 return null;
269 }
270
271 Map<String, Class<?>> memberTypes = type.memberTypes();
272 Map<String, Object> memberValues =
273 new LinkedHashMap<String, Object>(type.memberDefaults());
274
275 int numMembers = buf.getShort() & 0xFFFF;
276 for (int i = 0; i < numMembers; i++) {
277 int memberNameIndex = buf.getShort() & 0xFFFF;
278 String memberName = constPool.getUTF8At(memberNameIndex);
279 Class<?> memberType = memberTypes.get(memberName);
280
281 if (memberType == null) {
282 // Member is no longer present in annotation type; ignore it
822 skipAnnotation(buf, true);
823 break;
824 case '[':
825 skipArray(buf);
826 break;
827 default:
828 // Class, primitive, or String
829 buf.getShort();
830 }
831 }
832
833 /**
834 * Skips the array value at the current position in the specified byte
835 * buffer. The cursor of the byte buffer must point to an array value
836 * struct.
837 */
838 private static void skipArray(ByteBuffer buf) {
839 int length = buf.getShort() & 0xFFFF;
840 for (int i = 0; i < length; i++)
841 skipMemberValue(buf);
842 }
843
844 /**
845 * Searches for given {@code element} in given {@code array} by identity.
846 * Returns {@code true} if found {@code false} if not.
847 */
848 private static boolean contains(Object[] array, Object element) {
849 for (Object e : array)
850 if (e == element)
851 return true;
852 return false;
853 }
854
855 /*
856 * This method converts the annotation map returned by the parseAnnotations()
857 * method to an array. It is called by Field.getDeclaredAnnotations(),
858 * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
859 * This avoids the reflection classes to load the Annotation class until
860 * it is needed.
861 */
862 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
863 public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
864 return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
865 }
866
867 static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
868 }
|