1 /*
2 * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
50 /**
51 * Parses the annotations described by the specified byte array.
52 * resolving constant references in the specified constant pool.
53 * The array must contain an array of annotations as described
54 * in the RuntimeVisibleAnnotations_attribute:
55 *
56 * u2 num_annotations;
57 * annotation annotations[num_annotations];
58 *
59 * @throws AnnotationFormatError if an annotation is found to be
60 * malformed.
61 */
62 public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
63 byte[] rawAnnotations,
64 ConstantPool constPool,
65 Class<?> container) {
66 if (rawAnnotations == null)
67 return Collections.emptyMap();
68
69 try {
70 return parseAnnotations2(rawAnnotations, constPool, container);
71 } catch(BufferUnderflowException e) {
72 throw new AnnotationFormatError("Unexpected end of annotations.");
73 } catch(IllegalArgumentException e) {
74 // Type mismatch in constant pool
75 throw new AnnotationFormatError(e);
76 }
77 }
78
79 private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
80 byte[] rawAnnotations,
81 ConstantPool constPool,
82 Class<?> container) {
83 Map<Class<? extends Annotation>, Annotation> result =
84 new LinkedHashMap<Class<? extends Annotation>, Annotation>();
85 ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
86 int numAnnotations = buf.getShort() & 0xFFFF;
87 for (int i = 0; i < numAnnotations; i++) {
88 Annotation a = parseAnnotation(buf, constPool, container, false);
89 if (a != null) {
90 Class<? extends Annotation> klass = a.annotationType();
91 AnnotationType type = AnnotationType.getInstance(klass);
92 if (type.retention() == RetentionPolicy.RUNTIME)
93 if (result.put(klass, a) != null)
94 throw new AnnotationFormatError(
95 "Duplicate annotation for class: "+klass+": " + a);
96 }
97 }
98 return result;
99 }
100
101 /**
102 * Parses the parameter annotations described by the specified byte array.
103 * resolving constant references in the specified constant pool.
104 * The array must contain an array of annotations as described
105 * in the RuntimeVisibleParameterAnnotations_attribute:
106 *
107 * u1 num_parameters;
108 * {
109 * u2 num_annotations;
110 * annotation annotations[num_annotations];
111 * } parameter_annotations[num_parameters];
112 *
113 * Unlike parseAnnotations, rawAnnotations must not be null!
114 * A null value must be handled by the caller. This is so because
115 * we cannot determine the number of parameters if rawAnnotations
116 * is null. Also, the caller should check that the number
117 * of parameters indicated by the return value of this method
174 * annotation {
175 * u2 type_index;
176 * u2 num_member_value_pairs;
177 * { u2 member_name_index;
178 * member_value value;
179 * } member_value_pairs[num_member_value_pairs];
180 * }
181 * }
182 *
183 * Returns the annotation, or null if the annotation's type cannot
184 * be found by the VM, or is not a valid annotation type.
185 *
186 * @param exceptionOnMissingAnnotationClass if true, throw
187 * TypeNotPresentException if a referenced annotation type is not
188 * available at runtime
189 */
190 private static Annotation parseAnnotation(ByteBuffer buf,
191 ConstantPool constPool,
192 Class<?> container,
193 boolean exceptionOnMissingAnnotationClass) {
194 int typeIndex = buf.getShort() & 0xFFFF;
195 Class<? extends Annotation> annotationClass = null;
196 String sig = "[unknown]";
197 try {
198 try {
199 sig = constPool.getUTF8At(typeIndex);
200 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
201 } catch (IllegalArgumentException ex) {
202 // support obsolete early jsr175 format class files
203 annotationClass = constPool.getClassAt(typeIndex);
204 }
205 } catch (NoClassDefFoundError e) {
206 if (exceptionOnMissingAnnotationClass)
207 // note: at this point sig is "[unknown]" or VM-style
208 // name instead of a binary name
209 throw new TypeNotPresentException(sig, e);
210 skipAnnotation(buf, false);
211 return null;
212 }
213 catch (TypeNotPresentException e) {
214 if (exceptionOnMissingAnnotationClass)
215 throw e;
216 skipAnnotation(buf, false);
217 return null;
218 }
219 AnnotationType type = null;
220 try {
221 type = AnnotationType.getInstance(annotationClass);
222 } catch (IllegalArgumentException e) {
223 skipAnnotation(buf, false);
224 return null;
225 }
226
227 Map<String, Class<?>> memberTypes = type.memberTypes();
228 Map<String, Object> memberValues =
229 new LinkedHashMap<String, Object>(type.memberDefaults());
230
231 int numMembers = buf.getShort() & 0xFFFF;
232 for (int i = 0; i < numMembers; i++) {
233 int memberNameIndex = buf.getShort() & 0xFFFF;
234 String memberName = constPool.getUTF8At(memberNameIndex);
235 Class<?> memberType = memberTypes.get(memberName);
236
237 if (memberType == null) {
238 // Member is no longer present in annotation type; ignore it
774 case '[':
775 skipArray(buf);
776 break;
777 default:
778 // Class, primitive, or String
779 buf.getShort();
780 }
781 }
782
783 /**
784 * Skips the array value at the current position in the specified byte
785 * buffer. The cursor of the byte buffer must point to an array value
786 * struct.
787 */
788 private static void skipArray(ByteBuffer buf) {
789 int length = buf.getShort() & 0xFFFF;
790 for (int i = 0; i < length; i++)
791 skipMemberValue(buf);
792 }
793
794 /*
795 * This method converts the annotation map returned by the parseAnnotations()
796 * method to an array. It is called by Field.getDeclaredAnnotations(),
797 * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
798 * This avoids the reflection classes to load the Annotation class until
799 * it is needed.
800 */
801 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
802 public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
803 return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
804 }
805 }
|
1 /*
2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
50 /**
51 * Parses the annotations described by the specified byte array.
52 * resolving constant references in the specified constant pool.
53 * The array must contain an array of annotations as described
54 * in the RuntimeVisibleAnnotations_attribute:
55 *
56 * u2 num_annotations;
57 * annotation annotations[num_annotations];
58 *
59 * @throws AnnotationFormatError if an annotation is found to be
60 * malformed.
61 */
62 public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
63 byte[] rawAnnotations,
64 ConstantPool constPool,
65 Class<?> container) {
66 if (rawAnnotations == null)
67 return Collections.emptyMap();
68
69 try {
70 return parseAnnotations2(rawAnnotations, constPool, container, null);
71 } catch(BufferUnderflowException e) {
72 throw new AnnotationFormatError("Unexpected end of annotations.");
73 } catch(IllegalArgumentException e) {
74 // Type mismatch in constant pool
75 throw new AnnotationFormatError(e);
76 }
77 }
78
79 /**
80 * Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
81 * with an additional parameter {@code selectAnnotationClasses} which selects the
82 * annotation types to parse (other than selected are quickly skipped).<p>
83 * This method is only used to parse select meta annotations in the construction
84 * phase of {@link AnnotationType} instances to prevent infinite recursion.
85 *
86 * @param selectAnnotationClasses an array of annotation types to select when parsing
87 */
88 @SafeVarargs
89 static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
90 byte[] rawAnnotations,
91 ConstantPool constPool,
92 Class<?> container,
93 Class<? extends Annotation> ... selectAnnotationClasses) {
94 if (rawAnnotations == null)
95 return Collections.emptyMap();
96
97 try {
98 return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
99 } catch(BufferUnderflowException e) {
100 throw new AnnotationFormatError("Unexpected end of annotations.");
101 } catch(IllegalArgumentException e) {
102 // Type mismatch in constant pool
103 throw new AnnotationFormatError(e);
104 }
105 }
106
107 private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
108 byte[] rawAnnotations,
109 ConstantPool constPool,
110 Class<?> container,
111 Class<? extends Annotation>[] selectAnnotationClasses) {
112 Map<Class<? extends Annotation>, Annotation> result =
113 new LinkedHashMap<Class<? extends Annotation>, Annotation>();
114 ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
115 int numAnnotations = buf.getShort() & 0xFFFF;
116 for (int i = 0; i < numAnnotations; i++) {
117 Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
118 if (a != null) {
119 Class<? extends Annotation> klass = a.annotationType();
120 if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
121 result.put(klass, a) != null) {
122 throw new AnnotationFormatError(
123 "Duplicate annotation for class: "+klass+": " + a);
124 }
125 }
126 }
127 return result;
128 }
129
130 /**
131 * Parses the parameter annotations described by the specified byte array.
132 * resolving constant references in the specified constant pool.
133 * The array must contain an array of annotations as described
134 * in the RuntimeVisibleParameterAnnotations_attribute:
135 *
136 * u1 num_parameters;
137 * {
138 * u2 num_annotations;
139 * annotation annotations[num_annotations];
140 * } parameter_annotations[num_parameters];
141 *
142 * Unlike parseAnnotations, rawAnnotations must not be null!
143 * A null value must be handled by the caller. This is so because
144 * we cannot determine the number of parameters if rawAnnotations
145 * is null. Also, the caller should check that the number
146 * of parameters indicated by the return value of this method
203 * annotation {
204 * u2 type_index;
205 * u2 num_member_value_pairs;
206 * { u2 member_name_index;
207 * member_value value;
208 * } member_value_pairs[num_member_value_pairs];
209 * }
210 * }
211 *
212 * Returns the annotation, or null if the annotation's type cannot
213 * be found by the VM, or is not a valid annotation type.
214 *
215 * @param exceptionOnMissingAnnotationClass if true, throw
216 * TypeNotPresentException if a referenced annotation type is not
217 * available at runtime
218 */
219 private static Annotation parseAnnotation(ByteBuffer buf,
220 ConstantPool constPool,
221 Class<?> container,
222 boolean exceptionOnMissingAnnotationClass) {
223 return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
224 }
225
226 @SuppressWarnings("unchecked")
227 private static Annotation parseAnnotation2(ByteBuffer buf,
228 ConstantPool constPool,
229 Class<?> container,
230 boolean exceptionOnMissingAnnotationClass,
231 Class<? extends Annotation>[] selectAnnotationClasses) {
232 int typeIndex = buf.getShort() & 0xFFFF;
233 Class<? extends Annotation> annotationClass = null;
234 String sig = "[unknown]";
235 try {
236 try {
237 sig = constPool.getUTF8At(typeIndex);
238 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
239 } catch (IllegalArgumentException ex) {
240 // support obsolete early jsr175 format class files
241 annotationClass = constPool.getClassAt(typeIndex);
242 }
243 } catch (NoClassDefFoundError e) {
244 if (exceptionOnMissingAnnotationClass)
245 // note: at this point sig is "[unknown]" or VM-style
246 // name instead of a binary name
247 throw new TypeNotPresentException(sig, e);
248 skipAnnotation(buf, false);
249 return null;
250 }
251 catch (TypeNotPresentException e) {
252 if (exceptionOnMissingAnnotationClass)
253 throw e;
254 skipAnnotation(buf, false);
255 return null;
256 }
257 if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
258 skipAnnotation(buf, false);
259 return null;
260 }
261 AnnotationType type = null;
262 try {
263 type = AnnotationType.getInstance(annotationClass);
264 } catch (IllegalArgumentException e) {
265 skipAnnotation(buf, false);
266 return null;
267 }
268
269 Map<String, Class<?>> memberTypes = type.memberTypes();
270 Map<String, Object> memberValues =
271 new LinkedHashMap<String, Object>(type.memberDefaults());
272
273 int numMembers = buf.getShort() & 0xFFFF;
274 for (int i = 0; i < numMembers; i++) {
275 int memberNameIndex = buf.getShort() & 0xFFFF;
276 String memberName = constPool.getUTF8At(memberNameIndex);
277 Class<?> memberType = memberTypes.get(memberName);
278
279 if (memberType == null) {
280 // Member is no longer present in annotation type; ignore it
816 case '[':
817 skipArray(buf);
818 break;
819 default:
820 // Class, primitive, or String
821 buf.getShort();
822 }
823 }
824
825 /**
826 * Skips the array value at the current position in the specified byte
827 * buffer. The cursor of the byte buffer must point to an array value
828 * struct.
829 */
830 private static void skipArray(ByteBuffer buf) {
831 int length = buf.getShort() & 0xFFFF;
832 for (int i = 0; i < length; i++)
833 skipMemberValue(buf);
834 }
835
836 /**
837 * Searches for given {@code element} in given {@code array} by identity.
838 * Returns {@code true} if found {@code false} if not.
839 */
840 private static boolean contains(Object[] array, Object element) {
841 for (Object e : array)
842 if (e == element)
843 return true;
844 return false;
845 }
846
847 /*
848 * This method converts the annotation map returned by the parseAnnotations()
849 * method to an array. It is called by Field.getDeclaredAnnotations(),
850 * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
851 * This avoids the reflection classes to load the Annotation class until
852 * it is needed.
853 */
854 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
855 public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
856 return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
857 }
858 }
|