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