View Javadoc
1   package org.codehaus.plexus.util;
2   
3   /*
4    * Copyright The Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.lang.reflect.Field;
20  import java.lang.reflect.Method;
21  import java.lang.reflect.Modifier;
22  import java.lang.reflect.AccessibleObject;
23  import java.util.Map;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  
29  /**
30   * Operations on a class' fields and their setters.
31   * 
32   * @author <a href="mailto:michal@codehaus.org">Michal Maczka</a>
33   * @author <a href="mailto:jesse@codehaus.org">Jesse McConnell</a>
34   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
35   * @version $Id$
36   */
37  public final class ReflectionUtils
38  {
39      // ----------------------------------------------------------------------
40      // Field utils
41      // ----------------------------------------------------------------------
42  
43      public static Field getFieldByNameIncludingSuperclasses( String fieldName, Class<?> clazz )
44      {
45          Field retValue = null;
46  
47          try
48          {
49              retValue = clazz.getDeclaredField( fieldName );
50          }
51          catch ( NoSuchFieldException e )
52          {
53              Class<?> superclass = clazz.getSuperclass();
54  
55              if ( superclass != null )
56              {
57                  retValue = getFieldByNameIncludingSuperclasses( fieldName, superclass );
58              }
59          }
60  
61          return retValue;
62      }
63  
64      public static List<Field> getFieldsIncludingSuperclasses( Class<?> clazz )
65      {
66          List<Field> fields = new ArrayList<Field>( Arrays.asList( clazz.getDeclaredFields() ) );
67  
68          Class<?> superclass = clazz.getSuperclass();
69  
70          if ( superclass != null )
71          {
72              fields.addAll( getFieldsIncludingSuperclasses( superclass ) );
73          }
74  
75          return fields;
76      }
77  
78      // ----------------------------------------------------------------------
79      // Setter utils
80      // ----------------------------------------------------------------------
81  
82      /**
83       * Finds a setter in the given class for the given field. It searches interfaces and superclasses too.
84       *
85       * @param fieldName the name of the field (i.e. 'fooBar'); it will search for a method named 'setFooBar'.
86       * @param clazz The class to find the method in.
87       * @return null or the method found.
88       */
89      public static Method getSetter( String fieldName, Class<?> clazz )
90      {
91          Method[] methods = clazz.getMethods();
92  
93          fieldName = "set" + StringUtils.capitalizeFirstLetter( fieldName );
94  
95          for ( Method method : methods )
96          {
97              if ( method.getName().equals( fieldName ) && isSetter( method ) )
98              {
99                  return method;
100             }
101         }
102 
103         return null;
104     }
105 
106     /**
107      * Finds all setters in the given class and super classes.
108      */
109     public static List<Method> getSetters( Class<?> clazz )
110     {
111         Method[] methods = clazz.getMethods();
112 
113         List<Method> list = new ArrayList<Method>();
114 
115         for ( Method method : methods )
116         {
117             if ( isSetter( method ) )
118             {
119                 list.add( method );
120             }
121         }
122 
123         return list;
124     }
125 
126     /**
127      * Returns the class of the argument to the setter. Will throw an RuntimeException if the method isn't a setter.
128      */
129     public static Class<?> getSetterType( Method method )
130     {
131         if ( !isSetter( method ) )
132         {
133             throw new RuntimeException( "The method " + method.getDeclaringClass().getName() + "." + method.getName()
134                 + " is not a setter." );
135         }
136 
137         return method.getParameterTypes()[0];
138     }
139 
140     // ----------------------------------------------------------------------
141     // Value accesstors
142     // ----------------------------------------------------------------------
143 
144     /**
145      * attempts to set the value to the variable in the object passed in
146      *
147      * @param object
148      * @param variable
149      * @param value
150      * @throws IllegalAccessException
151      */
152     public static void setVariableValueInObject( Object object, String variable, Object value )
153         throws IllegalAccessException
154     {
155         Field field = getFieldByNameIncludingSuperclasses( variable, object.getClass() );
156 
157         field.setAccessible( true );
158 
159         field.set( object, value );
160     }
161 
162     /**
163      * Generates a map of the fields and values on a given object, also pulls from superclasses
164      *
165      * @param object the object to generate the list of fields from
166      * @return map containing the fields and their values
167      */
168     public static Object getValueIncludingSuperclasses( String variable, Object object )
169         throws IllegalAccessException
170     {
171 
172         Field field = getFieldByNameIncludingSuperclasses( variable, object.getClass() );
173 
174         field.setAccessible( true );
175 
176         return field.get( object );
177     }
178 
179     /**
180      * Generates a map of the fields and values on a given object, also pulls from superclasses
181      *
182      * @param object the object to generate the list of fields from
183      * @return map containing the fields and their values
184      */
185     public static Map<String, Object> getVariablesAndValuesIncludingSuperclasses( Object object )
186         throws IllegalAccessException
187     {
188         Map<String, Object> map = new HashMap<String, Object>();
189 
190         gatherVariablesAndValuesIncludingSuperclasses( object, map );
191 
192         return map;
193     }
194 
195     // ----------------------------------------------------------------------
196     // Private
197     // ----------------------------------------------------------------------
198 
199     public static boolean isSetter( Method method )
200     {
201         return method.getReturnType().equals( Void.TYPE ) && // FIXME: needed /required?
202             !Modifier.isStatic( method.getModifiers() ) && method.getParameterTypes().length == 1;
203     }
204 
205     /**
206      * populates a map of the fields and values on a given object, also pulls from superclasses
207      *
208      * @param object the object to generate the list of fields from
209      * @param map to populate
210      */
211     private static void gatherVariablesAndValuesIncludingSuperclasses( Object object, Map<String, Object> map )
212         throws IllegalAccessException
213     {
214 
215         Class<?> clazz = object.getClass();
216 
217         Field[] fields = clazz.getDeclaredFields();
218 
219         AccessibleObject.setAccessible( fields, true );
220 
221         for ( Field field : fields )
222         {
223             map.put( field.getName(), field.get( object ) );
224 
225         }
226 
227         Class<?> superclass = clazz.getSuperclass();
228 
229         if ( !Object.class.equals( superclass ) )
230         {
231             gatherVariablesAndValuesIncludingSuperclasses( superclass, map );
232         }
233     }
234 }