/*
* Copyright 2011 Martin Grotzke
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.hashcode.validation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.persistence.Id;
/**
* A utility class for reflection tasks.
*
* @author Martin Grotzke
*/
public class ReflectionUtils {
private ReflectionUtils() {
// utility class
}
/**
* Determines which field of the given class is annotated with {@link Id},
* including the inheritence tree up to {@link Object}.
*
* @return the Id field, never <code>null</code>.
* @throws IllegalArgumentException
* thrown if there's no field annotated with {@link Id}.
*/
public static Field getIdField(final Class<?> entityClass) throws IllegalArgumentException {
final Field[] fields = entityClass.getDeclaredFields();
for (final Field field : fields) {
final Id annotation = field.getAnnotation(Id.class);
if (annotation != null) {
return field;
}
}
if (entityClass.getSuperclass() != Object.class) {
return getIdField(entityClass.getSuperclass());
}
throw new IllegalArgumentException("No id field found on class " + entityClass);
}
/**
* Read the value of the specified propertyName from the given object. This
* implementation allows properties/fields with only getters (immutable
* beans) and does not rely on java beans standard (PropertyDescriptor)
* which would require also a setter method (the alternative would be s.th.
* like
* <code>new PropertyDescriptor(propertyName, entityClass).getReadMethod().invoke(target);</code>
* ).
*/
@CheckForNull
public static Object getPropertyValue(@Nonnull final Object object, @Nonnull final String propertyName)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
final Method method = getGetter(object.getClass(), propertyName);
return method.invoke(object, (Object[]) null);
}
@Nonnull
private static String toMethodName(@Nonnull final String methodPrefix, @Nonnull final String propertyName) {
return methodPrefix + propertyName.substring(0, 1).toUpperCase(Locale.ENGLISH) + propertyName.substring(1);
}
@Nonnull
private static Method getGetter(@Nonnull final Class<?> clazz, @Nonnull final String property) {
final String get = toMethodName("get", property);
final String is = toMethodName("is", property);
Method getter;
try {
getter = clazz.getMethod(get);
} catch (final NoSuchMethodException noSuchMethodException) {
try {
getter = clazz.getMethod(is);
} catch (final NoSuchMethodException noSuchMethodException2) {
throw new RuntimeException("Getter for '" + clazz.getSimpleName() + '#' + property + "' not found.",
noSuchMethodException2);
} catch (final SecurityException securityException) {
throw new RuntimeException("Method '" + clazz.getSimpleName() + '#' + is
+ "()' is protected by the security manager.");
}
} catch (final SecurityException securityException) {
try {
getter = clazz.getMethod(is);
} catch (final NoSuchMethodException noSuchMethodException) {
throw new RuntimeException("Method '" + clazz.getSimpleName() + '#' + get
+ "()' is protected by the security manager.");
} catch (final SecurityException securityException2) {
throw new RuntimeException("Methods '" + clazz.getSimpleName() + '#' + get + "()' and "
+ clazz.getSimpleName() + '#' + is + "()' are protected by the security manager.");
}
}
return getter;
}
}