001: /*******************************************************************************
002: * Portions created by Sebastian Thomschke are copyright (c) 2005-2007 Sebastian
003: * Thomschke.
004: *
005: * All Rights Reserved. This program and the accompanying materials
006: * are made available under the terms of the Eclipse Public License v1.0
007: * which accompanies this distribution, and is available at
008: * http://www.eclipse.org/legal/epl-v10.html
009: *
010: * Contributors:
011: * Sebastian Thomschke - initial implementation.
012: *******************************************************************************/package net.sf.oval.internal.util;
013:
014: import java.lang.reflect.Field;
015: import java.lang.reflect.Member;
016: import java.lang.reflect.Method;
017: import java.lang.reflect.Modifier;
018: import java.util.List;
019:
020: import net.sf.oval.context.FieldContext;
021: import net.sf.oval.context.MethodReturnValueContext;
022: import net.sf.oval.exception.AccessingFieldValueFailedException;
023: import net.sf.oval.exception.InvokingMethodFailedException;
024: import net.sf.oval.internal.CollectionFactoryHolder;
025: import net.sf.oval.internal.Log;
026:
027: /**
028: * @author Sebastian Thomschke
029: */
030: public final class ReflectionUtils {
031: private static final Log LOG = Log.getLog(ReflectionUtils.class);
032:
033: /**
034: * @return the field or null if the field does not exist
035: */
036: public static Field getField(final Class clazz,
037: final String fieldName) {
038: try {
039: return clazz.getDeclaredField(fieldName);
040: } catch (final NoSuchFieldException e) {
041: return null;
042: }
043: }
044:
045: /**
046: * @param setter
047: * @return Returns the corresponding field for a setter method. Returns null if the method is not a JavaBean style setter or the field could not be located.
048: */
049: public static Field getFieldForSetter(final Method setter) {
050: if (!ReflectionUtils.isSetter(setter))
051: return null;
052:
053: final Class[] methodParameterTypes = setter.getParameterTypes();
054: final String methodName = setter.getName();
055: final Class clazz = setter.getDeclaringClass();
056:
057: // calculate the corresponding field name based on the name of the setter method (e.g. method setName() => field
058: // name)
059: String fieldName = methodName.substring(3, 4).toLowerCase();
060: if (methodName.length() > 4) {
061: fieldName += methodName.substring(4);
062: }
063:
064: Field field = null;
065: try {
066: field = clazz.getDeclaredField(fieldName);
067:
068: // check if field and method parameter are of the same type
069: if (!field.getType().equals(methodParameterTypes[0])) {
070: if (LOG.isWarn())
071: LOG.warn("Found field <" + fieldName
072: + "> in class <" + clazz.getName()
073: + ">that matches setter <" + methodName
074: + "> name, but mismatches parameter type.");
075: field = null;
076: }
077: } catch (final NoSuchFieldException e) {
078: LOG.debug("Field not found", e);
079: }
080:
081: // if method parameter type is boolean then check if a field with name isXXX exists (e.g. method setEnabled() =>
082: // field isEnabled)
083: if (field == null
084: && (methodParameterTypes[0].equals(boolean.class) || methodParameterTypes[0]
085: .equals(Boolean.class))) {
086: fieldName = "is" + methodName.substring(3);
087:
088: try {
089: field = clazz.getDeclaredField(fieldName);
090:
091: // check if found field is of boolean or Boolean
092: if (!field.getType().equals(boolean.class)
093: && field.getType().equals(Boolean.class)) {
094: if (LOG.isWarn())
095: LOG
096: .warn("Found field <"
097: + fieldName
098: + "> that matches setter <"
099: + methodName
100: + "> name, but mismatches parameter type.");
101: field = null;
102: }
103: } catch (final NoSuchFieldException ex) {
104: LOG.debug("Field not found", ex);
105: }
106: }
107:
108: return field;
109: }
110:
111: public static Field getFieldRecursive(final Class clazz,
112: final String fieldName) {
113: final Field f = ReflectionUtils.getField(clazz, fieldName);
114: if (f != null)
115: return f;
116:
117: final Class super clazz = clazz.getSuperclass();
118: if (super clazz == null)
119: return null;
120:
121: return ReflectionUtils.getFieldRecursive(super clazz, fieldName);
122: }
123:
124: public static Object getFieldValue(final Field field,
125: final Object obj) throws AccessingFieldValueFailedException {
126: try {
127: if (!field.isAccessible())
128: field.setAccessible(true);
129: return field.get(obj);
130: } catch (final Exception ex) {
131: throw new AccessingFieldValueFailedException(field
132: .getName(), obj, new FieldContext(field), ex);
133: }
134: }
135:
136: public static List<Method> getInterfaceMethods(final Method method) {
137: // static methods cannot be overridden
138: if (ReflectionUtils.isStatic(method))
139: return null;
140:
141: final Class<?>[] interfaces = method.getDeclaringClass()
142: .getInterfaces();
143: if (interfaces.length == 0)
144: return null;
145:
146: final String methodName = method.getName();
147: final Class<?>[] parameterTypes = method.getParameterTypes();
148:
149: final List<Method> methods = CollectionFactoryHolder
150: .getFactory().createList(interfaces.length);
151: for (final Class iface : interfaces) {
152: final Method m = ReflectionUtils.getMethod(iface,
153: methodName, parameterTypes);
154: if (m != null)
155: methods.add(m);
156: }
157: return methods;
158: }
159:
160: /**
161: * @return the method or null if the method does not exist
162: */
163: public static Method getMethod(final Class<?> clazz,
164: final String methodName, final Class<?>... parameterTypes)
165: throws SecurityException {
166: try {
167: return clazz.getDeclaredMethod(methodName, parameterTypes);
168: } catch (final NoSuchMethodException e) {
169: return null;
170: }
171: }
172:
173: public static Method getSuperMethod(final Method method) {
174: // static methods cannot be overridden
175: if (ReflectionUtils.isStatic(method))
176: return null;
177:
178: final String methodName = method.getName();
179: final Class<?>[] parameterTypes = method.getParameterTypes();
180:
181: Class<?> currentClass = method.getDeclaringClass();
182:
183: while (currentClass != null && currentClass != Object.class) {
184: currentClass = currentClass.getSuperclass();
185:
186: final Method m = ReflectionUtils.getMethod(currentClass,
187: methodName, parameterTypes);
188: if (m != null && !ReflectionUtils.isPrivate(m))
189: return m;
190: }
191: return null;
192: }
193:
194: public static String guessFieldName(final Method getter) {
195: String fieldName = getter.getName();
196:
197: if (fieldName.startsWith("get") && fieldName.length() > 3) {
198: fieldName = fieldName.substring(3);
199: if (fieldName.length() == 1)
200: fieldName = fieldName.toLowerCase();
201: else
202: fieldName = Character.toLowerCase(fieldName.charAt(0))
203: + fieldName.substring(1);
204: } else if (fieldName.startsWith("is") && fieldName.length() > 2) {
205: fieldName = fieldName.substring(2);
206: if (fieldName.length() == 1)
207: fieldName = fieldName.toLowerCase();
208: else
209: fieldName = Character.toLowerCase(fieldName.charAt(0))
210: + fieldName.substring(1);
211: }
212:
213: return fieldName;
214: }
215:
216: public static boolean hasField(final Class clazz,
217: final String fieldName) {
218: return ReflectionUtils.getField(clazz, fieldName) != null;
219: }
220:
221: public static boolean hasMethod(final Class<?> clazz,
222: final String methodName, final Class<?>... parameterTypes) {
223: return ReflectionUtils.getMethod(clazz, methodName,
224: parameterTypes) != null;
225: }
226:
227: /**
228: *
229: * @param method the method to invoke
230: * @param obj the object on which to invoke the method
231: * @param args the method arguments
232: * @return the return value of the invoked method
233: * @throws InvokingMethodFailedException
234: */
235: public static Object invokeMethod(final Method method,
236: final Object obj, final Object... args)
237: throws InvokingMethodFailedException {
238: try {
239: if (!method.isAccessible())
240: method.setAccessible(true);
241: return method.invoke(obj, args);
242: } catch (final Exception ex) {
243: throw new InvokingMethodFailedException("Executing method "
244: + method.getName() + " failed.", obj,
245: new MethodReturnValueContext(method), ex);
246: }
247: }
248:
249: public static boolean isClassPresent(final String className) {
250: try {
251: Class.forName(className);
252: return true;
253: } catch (final ClassNotFoundException e) {
254: return false;
255: }
256: }
257:
258: public static boolean isFinal(final Member member) {
259: return (member.getModifiers() & Modifier.FINAL) != 0;
260: }
261:
262: /**
263: * determines if a method is a JavaBean style getter method
264: */
265: public static boolean isGetter(final Method method) {
266: return method.getParameterTypes().length == 0
267: && (method.getName().startsWith("is") || method
268: .getName().startsWith("get"));
269: }
270:
271: public static boolean isPackage(final Member member) {
272: return (member.getModifiers() & (Modifier.PUBLIC
273: | Modifier.PRIVATE | Modifier.PROTECTED)) == 0;
274: }
275:
276: public static boolean isPrivate(final Member member) {
277: return (member.getModifiers() & Modifier.PRIVATE) != 0;
278: }
279:
280: public static boolean isProtected(final Member member) {
281: return (member.getModifiers() & Modifier.PROTECTED) != 0;
282: }
283:
284: /**
285: * determines if a method is a JavaBean style setter method
286: */
287: public static boolean isSetter(final Method method) {
288: final Class[] methodParameterTypes = method.getParameterTypes();
289:
290: // check if method has exactly one parameter
291: if (methodParameterTypes.length != 1)
292: return false;
293:
294: final String methodName = method.getName();
295: final int methodNameLen = methodName.length();
296:
297: // check if the method's name starts with setXXX
298: if (methodNameLen < 4 || !methodName.startsWith("set"))
299: return false;
300:
301: return true;
302: }
303:
304: public static boolean isStatic(final Member member) {
305: return (member.getModifiers() & Modifier.STATIC) != 0;
306: }
307:
308: public static boolean isTransient(final Member member) {
309: return (member.getModifiers() & Modifier.TRANSIENT) != 0;
310: }
311:
312: /**
313: * determines if a method is a void method
314: */
315: public static boolean isVoidMethod(final Method method) {
316: return method.getReturnType() == void.class;
317: }
318:
319: private ReflectionUtils() {
320: // do nothing
321: }
322: }
|