001 package edu.rice.cs.cunit.subAnnot;
002
003 import edu.rice.cs.cunit.classFile.attributes.AAnnotationsAttributeInfo;
004 import edu.rice.cs.cunit.classFile.attributes.AMultipleNamedAnnotationsAttributeInfo;
005 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleLocalVariableAnnotationsAttributeInfo;
006 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleParameterAnnotationsAttributeInfo;
007
008 import java.lang.annotation.Annotation;
009 import java.lang.reflect.*;
010 import java.util.ArrayList;
011 import java.util.HashMap;
012 import java.util.List;
013 import java.util.Map;
014
015 /**
016 * Extended Constructor class to support annotations with subclassing.
017 *
018 * @author Mathias Ricken
019 */
020 public class ConstructorEx<T> extends AAnnotatedElementEx {
021 /**
022 * The java.lang.reflect.Constructor object that represents the constructor.
023 */
024 public final Constructor<T> java;
025
026 /**
027 * Parameter annotation attribute.
028 */
029 private RuntimeVisibleParameterAnnotationsAttributeInfo _pai;
030
031 /**
032 * Local variable annotation attribute.
033 */
034 private RuntimeVisibleLocalVariableAnnotationsAttributeInfo _lvai;
035
036 /**
037 * Create an extended Constructor instance for the specified c.
038 * @param c constructor.
039 */
040 public ConstructorEx(Constructor<T> c) {
041 this(c, null);
042 }
043 /**
044 * Create an extended Constructor instance for the specified c.
045 * @param c constructor.
046 * @param cl class loader
047 */
048 public ConstructorEx(Constructor<T> c, ClassLoader cl) {
049 super(cl);
050 java = c;
051 findMethodAnnotationsAttributeInfo(c, "<init>", c.getParameterTypes());
052 _pai = getParameterAnnotationsAttributeInfo(c, "<init>", c.getParameterTypes());
053 _lvai = getLocalVarAnnotationsAttributeInfo(c, "<init>", c.getParameterTypes());
054 }
055
056
057 /**
058 * Return the annotated element.
059 * @return annotated element
060 */
061 protected AnnotatedElement getAnnotatedElement() {
062 return java;
063 }
064
065 /**
066 * Returns the name of this constructor, as a string. This is always the same as the simple name of the
067 * constructor's declaring class.
068 * @return name
069 */
070 public String getName() {
071 return java.getName();
072 }
073
074 /**
075 * Returns the Java language modifiers for the constructor represented by this <code>Constructor</code> object, as
076 * an integer. The <code>Modifier</code> class should be used to decode the modifiers.
077 * @return modifiers
078 * @see java.lang.reflect.Modifier
079 */
080 public int getModifiers() {
081 return java.getModifiers();
082 }
083
084 /**
085 * Returns an array of <tt>TypeVariable</tt> objects that represent the type variables declared by the generic
086 * declaration represented by this <tt>GenericDeclaration</tt> object, in declaration order. Returns an array of
087 * length 0 if the underlying generic declaration declares no type variables.
088 *
089 * @return an array of <tt>TypeVariable</tt> objects that represent the type variables declared by this generic
090 * declaration
091 *
092 * @throws java.lang.reflect.GenericSignatureFormatError
093 * if the generic signature of this generic declaration does not conform to the format specified in the Java
094 * Virtual Machine Specification, 3rd edition
095 */
096 public TypeVariable[] getTypeParameters() {
097 return java.getTypeParameters();
098 }
099
100 /**
101 * Returns an array of <tt>Type</tt> objects that represent the formal parameter types, in declaration order, of the
102 * method represented by this <tt>Constructor</tt> object. Returns an array of length 0 if the underlying method takes
103 * no parameters.
104 * <p/>
105 * <p>If a formal parameter type is a parameterized type, the <tt>Type</tt> object returned for it must accurately
106 * reflect the actual type parameters used in the source code.
107 * <p/>
108 * <p>If a formal parameter type is a type variable or a parameterized type, it is created. Otherwise, it is resolved.
109 *
110 * @return an array of <tt>Type</tt>s that represent the formal parameter types of the underlying method, in
111 * declaration order
112 *
113 * @throws java.lang.reflect.GenericSignatureFormatError
114 * if the generic method signature does not conform to the format specified in the Java
115 * Virtual Machine Specification, 3rd edition
116 * @throws TypeNotPresentException if any of the parameter types of the underlying method refers to a non-existent type
117 * declaration
118 * @throws java.lang.reflect.MalformedParameterizedTypeException
119 * if any of the underlying method's parameter types refer to a parameterized type that
120 * cannot be instantiated for any reason
121 */
122 public Type[] getGenericParameterTypes() {
123 return java.getGenericParameterTypes();
124 }
125
126 /**
127 * Returns an array of <code>Class</code> objects that represent the types of exceptions declared to be thrown by
128 * the underlying constructor represented by this <code>Constructor</code> object. Returns an array of length 0 if
129 * the constructor declares no exceptions in its <code>throws</code> clause.
130 *
131 * @return the exception types declared as being thrown by the constructor this object represents
132 */
133 @SuppressWarnings("unchecked")
134 public ClassEx[] getExceptionTypes() {
135 List<ClassEx> list = new ArrayList<ClassEx>();
136 for(Class c: java.getExceptionTypes()) {
137 list.add(new ClassEx(c, _classLoader));
138 }
139 return list.toArray(new ClassEx[list.size()]);
140 }
141
142 /**
143 * Returns an array of <tt>Type</tt> objects that represent the exceptions declared to be thrown by this
144 * <tt>Constructor</tt> object. Returns an array of length 0 if the underlying method declares no exceptions in its
145 * <tt>throws</tt> clause.
146 * <p/>
147 * <p>If an exception type is a parameterized type, the <tt>Type</tt> object returned for it must accurately reflect
148 * the actual type parameters used in the source code.
149 * <p/>
150 * <p>If an exception type is a type variable or a parameterized type, it is created. Otherwise, it is resolved.
151 *
152 * @return an array of Types that represent the exception types thrown by the underlying method
153 *
154 * @throws java.lang.reflect.GenericSignatureFormatError
155 * if the generic method signature does not conform to the format specified in the Java
156 * Virtual Machine Specification, 3rd edition
157 * @throws TypeNotPresentException if the underlying method's <tt>throws</tt> clause refers to a non-existent type
158 * declaration
159 * @throws java.lang.reflect.MalformedParameterizedTypeException
160 * if the underlying method's <tt>throws</tt> clause refers to a parameterized type
161 * that cannot be instantiated for any reason
162 */
163 public Type[] getGenericExceptionTypes() {
164 return java.getGenericExceptionTypes();
165 }
166
167 /**
168 * Compares this <code>Constructor</code> against the specified object. Returns true if the objects are the same. Two
169 * <code>Constructor</code> objects are the same if they were declared by the same class and have the same formal
170 * parameter types.
171 */
172 public boolean equals(Object obj) {
173 return (obj!=null)&&(obj.getClass().equals(this.getClass()) && (java.equals(obj)));
174 }
175
176 /**
177 * Returns a hashcode for this <code>Constructor</code>. The hashcode is the same as the hashcode for the underlying
178 * constructor's declaring class name.
179 */
180 public int hashCode() {
181 return java.hashCode();
182 }
183
184 /**
185 * Returns a string describing this <code>Constructor</code>. The string is formatted as the constructor access
186 * modifiers, if any, followed by the fully-qualified name of the declaring class, followed by a parenthesized,
187 * comma-separated list of the constructor's formal parameter types. For example:
188 * <pre>
189 * public java.util.Hashtable(int,float)
190 * </pre>
191 * <p/>
192 * <p>The only possible modifiers for constructors are the access modifiers <tt>public</tt>, <tt>protected</tt> or
193 * <tt>private</tt>. Only one of these may appear, or none if the constructor has default (package) access.
194 */
195 public String toString() {
196 return java.toString();
197 }
198
199 /**
200 * Returns a string describing this <code>Constructor</code>, including type parameters. The string is formatted as
201 * the constructor access modifiers, if any, followed by an angle-bracketed comma separated list of the
202 * constructor's type parameters, if any, followed by the fully-qualified name of the declaring class, followed by a
203 * parenthesized, comma-separated list of the constructor's generic formal parameter types. A space is used to
204 * separate access modifiers from one another and from the type parameters or return type. If there are no type
205 * parameters, the type parameter list is elided; if the type parameter list is present, a space separates the list
206 * from the class name. If the constructor is declared to throw exceptions, the parameter list is followed by a
207 * space, followed by the word "<tt>throws</tt>" followed by a comma-separated list of the thrown
208 * exception types.
209 * <p/>
210 * <p>The only possible modifiers for constructors are the access modifiers <tt>public</tt>, <tt>protected</tt> or
211 * <tt>private</tt>. Only one of these may appear, or none if the constructor has default (package) access.
212 *
213 * @return a string describing this <code>Constructor</code>, include type parameters
214 */
215 public String toGenericString() {
216 return java.toGenericString();
217 }
218
219 /**
220 * Uses the constructor represented by this <code>Constructor</code> object to create and initialize a new instance of
221 * the constructor's declaring class, with the specified initialization parameters. Individual parameters are
222 * automatically unwrapped to match primitive formal parameters, and both primitive and reference parameters are
223 * subject to method invocation conversions as necessary.
224 * <p/>
225 * <p>If the number of formal parameters required by the underlying constructor is 0, the supplied
226 * <code>initargs</code> array may be of length 0 or null.
227 * <p/>
228 * <p>If the required access and argument checks succeed and the instantiation will proceed, the constructor's
229 * declaring class is initialized if it has not already been initialized.
230 * <p/>
231 * <p>If the constructor completes normally, returns the newly created and initialized instance.
232 *
233 * @param initargs array of objects to be passed as arguments to the constructor call; values of primitive types are
234 * wrapped in a wrapper object of the appropriate type (e.g. a <tt>float</tt> in a {@link Float
235 * Float})
236 *
237 * @return a new object created by calling the constructor this object represents
238 *
239 * @throws IllegalAccessException if this <code>Constructor</code> object enforces Java language access control
240 * and the underlying constructor is inaccessible.
241 * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an unwrapping
242 * conversion for primitive arguments fails; or if, after possible unwrapping, a
243 * parameter value cannot be converted to the corresponding formal parameter type
244 * by a method invocation conversion; if this constructor pertains to an enum
245 * type.
246 * @throws InstantiationException if the class that declares the underlying constructor represents an abstract
247 * class.
248 * @throws java.lang.reflect.InvocationTargetException
249 * if the underlying constructor throws an exception.
250 * @throws ExceptionInInitializerError if the initialization provoked by this method fails.
251 */
252 public T newInstance(Object[] initargs) throws InstantiationException, IllegalAccessException,
253 IllegalArgumentException, InvocationTargetException {
254 return java.newInstance(initargs);
255 }
256
257 /**
258 * Returns <tt>true</tt> if this constructor was declared to take a variable number of arguments; returns
259 * <tt>false</tt> otherwise.
260 *
261 * @return <tt>true</tt> if an only if this constructor was declared to take a variable number of arguments.
262 */
263 public boolean isVarArgs() {
264 return java.isVarArgs();
265 }
266
267 /**
268 * Returns <tt>true</tt> if this constructor is a synthetic constructor; returns <tt>false</tt> otherwise.
269 *
270 * @return true if and only if this constructor is a synthetic constructor as defined by the Java Language
271 * Specification.
272 */
273 public boolean isSynthetic() {
274 return java.isSynthetic();
275 }
276
277
278 /**
279 * Returns an array of <code>Class</code> objects that represent the formal parameter types, in declaration order,
280 * of the constructor represented by this <code>Constructor</code> object. Returns an array of length 0 if the
281 * underlying constructor takes no parameters.
282 *
283 * @return the parameter types for the constructor this object represents
284 */
285 @SuppressWarnings("unchecked")
286 public ClassEx[] getParameterTypes() {
287 List<ClassEx> list = new ArrayList<ClassEx>();
288 for(Class c: java.getParameterTypes()) {
289 list.add(new ClassEx(c, _classLoader));
290 }
291 return list.toArray(new ClassEx[list.size()]);
292
293 }
294
295 /**
296 * Returns an array of arrays that represent the annotations on the formal parameters, in declaration order, of the
297 * method represented by this <tt>Method</tt> object. (Returns an array of length zero if the underlying method is
298 * parameterless. If the method has one or more parameters, a nested array of length zero is returned for each
299 * parameter with no annotations.) The annotation objects contained in the returned arrays are serializable. The
300 * caller of this method is free to modify the returned arrays; it will have no effect on the arrays returned to other
301 * callers.
302 *
303 * @return an array of arrays that represent the annotations on the formal parameters, in declaration order, of the
304 * method represented by this Method object
305 */
306 public Annotation[][] getParameterAnnotations() {
307 Annotation[][] ann = java.getParameterAnnotations();
308 Annotation[][] out = new Annotation[ann.length][];
309 for(int i=0; i<ann.length; ++i) {
310 out[i] = new Annotation[ann[i].length];
311 if (_pai!=null) {
312 for(int j=0; j<ann[i].length; ++j) {
313 out[i][j] = (Annotation)Proxy.newProxyInstance(ann[i][j].annotationType().getClassLoader(),
314 new Class[]{ann[i][j].annotationType()},
315 new AnnotationDynamicProxyHandler(ann[i][j].annotationType(),
316 _pai.getEntityAnnotations().get(i)[j]));
317 }
318 }
319 }
320 return out;
321 }
322
323 /**
324 * Returns a map from local variable names to arrays of annotations associated with them.
325 * @return map from local variable name to arrays of annotations
326 */
327 @SuppressWarnings("unchecked")
328 public Map<String,Annotation[]> getLocalVariableAnnotations() {
329 Map<String,Annotation[]> out = new HashMap<String,Annotation[]>();
330 if (_lvai!=null) {
331 for(AMultipleNamedAnnotationsAttributeInfo.NamedAnnotationsRecord nar: _lvai.getEntityAnnotations()) {
332 String name = nar.getName().toString();
333 Annotation[] arr = new Annotation[nar.getAnnotations().length];
334 for(int i=0; i<nar.getAnnotations().length; ++i) {
335 String t = nar.getAnnotations()[i].getType().replace('/','.').replace('$', '.');
336 // TODO: check for arrays of annotations
337 if ((t.length()==0) || (t.charAt(0)!='L')) {
338 throw new ClassFormatError("Unexpected type name for annotation: "+t);
339 }
340 t = t.substring(1,t.length()-1);
341 try {
342 Class c = Class.forName(t);
343 arr[i] = (Annotation)Proxy.newProxyInstance(c.getClassLoader(),
344 new Class[]{c},
345 new AnnotationDynamicProxyHandler(c,
346 nar.getAnnotations()[i]));
347 }
348 catch(ClassNotFoundException e) {
349 throw new ClassFormatError("Could not find class "+t);
350 }
351 }
352 out.put(name,arr);
353 }
354 }
355 return out;
356 }
357 }