View Javadoc

1   /*
2    * Copyright (C) The MetaClass Group. All rights reserved.
3    *
4    * This software is published under the terms of the Spice
5    * Software License version 1.1, a copy of which has been included
6    * with this distribution in the LICENSE.txt file.
7    */
8   package org.codehaus.metaclass;
9   
10  import java.lang.reflect.Constructor;
11  import java.lang.reflect.Field;
12  import java.lang.reflect.Method;
13  import java.util.ArrayList;
14  import org.codehaus.metaclass.introspector.MetaClassException;
15  import org.codehaus.metaclass.introspector.MetaClassIntrospector;
16  import org.codehaus.metaclass.model.Attribute;
17  import org.codehaus.metaclass.model.ClassDescriptor;
18  import org.codehaus.metaclass.model.FieldDescriptor;
19  import org.codehaus.metaclass.model.MethodDescriptor;
20  import org.codehaus.metaclass.model.ParameterDescriptor;
21  
22  /***
23   * Utility class to make it easy to access attributes for
24   * classes and methods. The utility class makes it possible
25   * to access attributes for methods and fields by using one
26   * method call such as;
27   * <pre>
28   *    //Get all Class attributes for 'MyClass'
29   *    Attribute[] attributes =
30   *           Attributes.getAttributes( MyClass.class );
31   *
32   *    //Get all Class attributes for 'MyClass'
33   *    //that have name 'dna.service'
34   *    Attribute[] attributes =
35   *           Attributes.getAttributes( MyClass.class, "dna.service" );
36   *
37   *    //Get attribute named 'dna.component' for 'MyClass'
38   *    //Note: that this may return null
39   *    Attribute attribute =
40   *           Attributes.getAttribute( MyClass.class, "dna.component" );
41   * </pre>
42   *
43   * <p>Note that none of the methods in this class throw an
44   * exception. If an error occurs retrieving attributes for
45   * a particular artefact (such as being unable to load
46   * ClassDescriptor for class) then either an empty array
47   * or a null will be returned depending on the method.</p>
48   *
49   * @version $Revision: 1.11 $ $Date: 2003/10/14 01:24:23 $
50   */
51  public class Attributes
52  {
53      /***
54       * Return the Attributes with specified name
55       * from specified attributes.
56       *
57       * @param attributes the attributes
58       * @param name the name of attribute to collect
59       * @return the attribute from set with specified name
60       */
61      public static Attribute getAttributeByName( final Attribute[] attributes,
62                                                  final String name )
63      {
64          for( int i = 0; i < attributes.length; i++ )
65          {
66              final Attribute attribute = attributes[ i ];
67              if( attribute.getName().equals( name ) )
68              {
69                  return attribute;
70              }
71          }
72          return null;
73      }
74  
75      /***
76       * Return the set of Attributes with specified name
77       * from specified attributes.
78       *
79       * @param attributes the attributes
80       * @param name the name of attributes to collect
81       * @return the attributes from set with specified name
82       */
83      public static Attribute[] getAttributesByName( final Attribute[] attributes,
84                                                     final String name )
85      {
86          final ArrayList results = new ArrayList();
87          for( int i = 0; i < attributes.length; i++ )
88          {
89              final Attribute attribute = attributes[ i ];
90              final String attributeName = attribute.getName();
91              if( attributeName.equals( name ) )
92              {
93                  results.add( attribute );
94              }
95          }
96          return (Attribute[])results.toArray( new Attribute[ results.size() ] );
97      }
98  
99      /***
100      * Return the attributes for specified Class.
101      *
102      * @param clazz the class
103      * @return the 'Class' attributes
104      */
105     public static Attribute[] getAttributes( final Class clazz )
106     {
107         try
108         {
109             final ClassDescriptor descriptor = getClassInfo( clazz );
110             return descriptor.getAttributes();
111         }
112         catch( final Exception e )
113         {
114             return Attribute.EMPTY_SET;
115         }
116     }
117 
118     /***
119      * Return the attributes for specified Class
120      * that have specified name.
121      *
122      * @param clazz the class
123      * @param name the attribute name
124      * @return the attributes
125      */
126     public static Attribute[] getAttributes( final Class clazz, final String name )
127     {
128         try
129         {
130             final ClassDescriptor descriptor = getClassInfo( clazz );
131             return getAttributesByName( descriptor.getAttributes(),
132                                         name );
133         }
134         catch( final Exception e )
135         {
136             return Attribute.EMPTY_SET;
137         }
138     }
139 
140     /***
141      * Return the attribute for specified Class
142      * that has the specified name. If there are multiple
143      * attributes with the same name then the first
144      * attribute will be returned.
145 
146      * @param clazz the class
147      * @param name the attribute name
148      * @return the attribute or null if no such attribute
149      */
150     public static Attribute getAttribute( final Class clazz,
151                                           final String name )
152     {
153         try
154         {
155             final ClassDescriptor descriptor = getClassInfo( clazz );
156             return getAttributeByName( descriptor.getAttributes(), name );
157         }
158         catch( final Exception e )
159         {
160             return null;
161         }
162     }
163 
164     /***
165      * Return the attributes for specified Class.
166      *
167      * @param field the field
168      * @return the 'Field' attributes
169      */
170     public static Attribute[] getAttributes( final Field field )
171     {
172         try
173         {
174             return getField( field ).getAttributes();
175         }
176         catch( final Exception e )
177         {
178             return Attribute.EMPTY_SET;
179         }
180     }
181 
182     /***
183      * Return the attributes for specified Field
184      * that have specified name.
185      *
186      * @param field the field
187      * @param name the attribute name
188      * @return the 'Field' attributes
189      */
190     public static Attribute[] getAttributes( final Field field,
191                                              final String name )
192     {
193         try
194         {
195             return getAttributesByName( getField( field ).getAttributes(), name );
196         }
197         catch( final Exception e )
198         {
199             return Attribute.EMPTY_SET;
200         }
201     }
202 
203     /***
204      * Return the attribute for specified Field
205      * that has the specified name. If there are multiple
206      * attributes with the same name then the first
207      * attribute will be returned.
208 
209      * @param field the field
210      * @param name the attribute name
211      * @return the attribute or null if no such attribute
212      */
213     public static Attribute getAttribute( final Field field,
214                                           final String name )
215     {
216         try
217         {
218             return getAttributeByName( getField( field ).getAttributes(), name );
219         }
220         catch( Exception e )
221         {
222             return null;
223         }
224     }
225 
226     /***
227      * Return the attributes for specified Method.
228      *
229      * @param method the method
230      * @return the 'Method' attributes
231      */
232     public static Attribute[] getAttributes( final Method method )
233     {
234         try
235         {
236             final MethodDescriptor descriptor = getMethod( method );
237             return descriptor.getAttributes();
238         }
239         catch( final Exception e )
240         {
241             return Attribute.EMPTY_SET;
242         }
243     }
244 
245     /***
246      * Return the attributes for specified Method
247      * that have specified name.
248      *
249      * @param method the Method
250      * @param name the attribute name
251      * @return the attributes
252      */
253     public static Attribute[] getAttributes( final Method method, final String name )
254     {
255         try
256         {
257             final MethodDescriptor descriptor = getMethod( method );
258             return getAttributesByName( descriptor.getAttributes(), name );
259         }
260         catch( Exception e )
261         {
262             return Attribute.EMPTY_SET;
263         }
264     }
265 
266     /***
267      * Return the attribute for specified Method
268      * that has the specified name. If there are multiple
269      * attributes with the same name then the first
270      * attribute will be returned.
271 
272      * @param method the method
273      * @param name the attribute name
274      * @return the attribute or null if no such attribute
275      */
276     public static Attribute getAttribute( final Method method, final String name )
277     {
278         try
279         {
280             final MethodDescriptor descriptor = getMethod( method );
281             return getAttributeByName( descriptor.getAttributes(), name );
282         }
283         catch( Exception e )
284         {
285             return null;
286         }
287     }
288 
289     /***
290      * Return the attributes for specified Constructor.
291      *
292      * @param constructor the constructor
293      * @return the 'Constructor' attributes
294      */
295     public static Attribute[] getAttributes( final Constructor constructor )
296     {
297         try
298         {
299             return getConstructor( constructor ).getAttributes();
300         }
301         catch( Exception e )
302         {
303             return Attribute.EMPTY_SET;
304         }
305     }
306 
307     /***
308      * Return the attributes for specified Constructor
309      * that have specified name.
310      *
311      * @param constructor the Constructor
312      * @param name the attribute name
313      * @return the attributes
314      */
315     public static Attribute[] getAttributes( final Constructor constructor,
316                                              final String name )
317     {
318         try
319         {
320             final Attribute[] attributes =
321                 getConstructor( constructor ).getAttributes();
322             return getAttributesByName( attributes, name );
323         }
324         catch( Exception e )
325         {
326             return Attribute.EMPTY_SET;
327         }
328     }
329 
330     /***
331      * Return the attribute for specified Constructor
332      * that has the specified name. If there are multiple
333      * attributes with the same name then the first
334      * attribute will be returned.
335 
336      * @param constructor the constructor
337      * @param name the attribute name
338      * @return the attribute or null if no such attribute
339      */
340     public static Attribute getAttribute( final Constructor constructor, final String name )
341     {
342         try
343         {
344             final Attribute[] attributes =
345                 getConstructor( constructor ).getAttributes();
346             return getAttributeByName( attributes, name );
347         }
348         catch( Exception e )
349         {
350             return null;
351         }
352     }
353 
354     /***
355      * Get the FieldDescriptor with specified name
356      * for specified Class.
357      *
358      * @param field the field
359      * @return the FieldDescriptor
360      * @throws MetaClassException if unable to locate FieldDescriptor for Field
361      */
362     public static FieldDescriptor getField( final Field field )
363         throws MetaClassException
364     {
365         final FieldDescriptor[] fields =
366             getClassInfo( field.getDeclaringClass() ).getFields();
367         for( int i = 0; i < fields.length; i++ )
368         {
369             final FieldDescriptor candidate = fields[ i ];
370             if( candidate.getName().equals( field.getName() ) )
371             {
372                 return candidate;
373             }
374         }
375         throw new MetaClassException( "No FieldDescriptor matching " + field );
376     }
377 
378     /***
379      * Get the MethodDescriptor for specified method.
380      *
381      * @param method the method
382      * @return the MethodDescriptor
383      * @throws MetaClassException if unable to locate MethodDescriptor for Method
384      */
385     public static MethodDescriptor getMethod( final Method method )
386         throws MetaClassException
387     {
388         final Class[] parameterTypes = method.getParameterTypes();
389 
390         final MethodDescriptor[] methods =
391             getClassInfo( method.getDeclaringClass() ).getMethods();
392         for( int i = 0; i < methods.length; i++ )
393         {
394             final MethodDescriptor candidate = methods[ i ];
395             final ParameterDescriptor[] parameters = candidate.getParameters();
396             if( candidate.getName().equals( method.getName() ) &&
397                 parameters.length == parameterTypes.length )
398             {
399                 boolean match = true;
400                 for( int j = 0; j < parameters.length; j++ )
401                 {
402                     final ParameterDescriptor parameter = parameters[ j ];
403                     final Class type = parameterTypes[ j ];
404                     if( !type.getName().equals( parameter.getType() ) )
405                     {
406                         match = false;
407                         break;
408                     }
409                 }
410                 if( match )
411                 {
412                     return candidate;
413                 }
414             }
415         }
416         throw new MetaClassException( "No MethodDescriptor matching " + method );
417     }
418 
419     /***
420      * Get the MethodDescriptor for specified Constructor.
421      *
422      * @param constructor the Constructor
423      * @return the MethodDescriptor
424      * @throws MetaClassException if unable to locate MethodDescriptor for Constructor
425      */
426     public static MethodDescriptor getConstructor( final Constructor constructor )
427         throws MetaClassException
428     {
429         String name = constructor.getName();
430         final int index = name.lastIndexOf( "." );
431         if( -1 != index )
432         {
433             name = name.substring( index + 1 );
434         }
435         final Class[] parameterTypes = constructor.getParameterTypes();
436         final MethodDescriptor[] methods =
437             getClassInfo( constructor.getDeclaringClass() ).getMethods();
438         for( int i = 0; i < methods.length; i++ )
439         {
440             final MethodDescriptor candidate = methods[ i ];
441             final ParameterDescriptor[] parameters = candidate.getParameters();
442             if( candidate.getName().equals( name ) &&
443                 parameters.length == parameterTypes.length )
444             {
445                 boolean match = true;
446                 for( int j = 0; j < parameters.length; j++ )
447                 {
448                     final String parameter = parameters[ j ].getType();
449                     final String type = parameterTypes[ j ].getName();
450                     if( !type.equals( parameter ) )
451                     {
452                         match = false;
453                         break;
454                     }
455                 }
456                 if( match )
457                 {
458                     return candidate;
459                 }
460             }
461         }
462         throw new MetaClassException( "No MethodDescriptor matching " + constructor );
463     }
464 
465     /***
466      * Utility method to get ClassDescriptor for specified class.
467      *
468      * @param clazz the class
469      * @return the ClassDescriptor
470      * @throws MetaClassException if unable to get ClassDescriptor
471      */
472     private static ClassDescriptor getClassInfo( final Class clazz )
473         throws MetaClassException
474     {
475         return MetaClassIntrospector.getClassDescriptor( clazz );
476     }
477 }