diff --git a/commons-annotations/src/main/java/org/hibernate/annotations/common/util/ReflectHelper.java b/commons-annotations/src/main/java/org/hibernate/annotations/common/util/ReflectHelper.java index 5bf6f878db..7affd0b8f7 100644 --- a/commons-annotations/src/main/java/org/hibernate/annotations/common/util/ReflectHelper.java +++ b/commons-annotations/src/main/java/org/hibernate/annotations/common/util/ReflectHelper.java @@ -23,8 +23,12 @@ */ package org.hibernate.annotations.common.util; -import java.lang.reflect.Method; import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.hibernate.AssertionFailure; +import org.hibernate.util.StringHelper; /** * Complete duplication of {@link org.hibernate.util.ReflectHelper}. @@ -32,47 +36,198 @@ import java.lang.reflect.Member; * @author Emmanuel Bernard */ public final class ReflectHelper { - public static boolean overridesEquals(Class clazz) { - return org.hibernate.util.ReflectHelper.overridesEquals( clazz ); - } - public static boolean overridesHashCode(Class clazz) { - return org.hibernate.util.ReflectHelper.overridesHashCode( clazz ); - } + public static final Class[] NO_PARAM_SIGNATURE = new Class[0]; + public static final Object[] NO_PARAMS = new Object[0]; - public static Class classForName(String name) throws ClassNotFoundException { - return ReflectHelper.classForName( name ); - } + public static final Class[] SINGLE_OBJECT_PARAM_SIGNATURE = new Class[] { Object.class }; - public static Class classForName(String name, Class caller) throws ClassNotFoundException { - return org.hibernate.util.ReflectHelper.classForName( name, caller ); - } + private static final Method OBJECT_EQUALS; + private static final Method OBJECT_HASHCODE; - public static boolean isPublic(Class clazz, Member member) { - return org.hibernate.util.ReflectHelper.isPublic( clazz, member ); - } - - public static Object getConstantValue(String name) { - return org.hibernate.util.ReflectHelper.getConstantValue( name ); - } - - public static boolean isAbstractClass(Class clazz) { - return org.hibernate.util.ReflectHelper.isAbstractClass( clazz ); - } - - public static boolean isFinalClass(Class clazz) { - return org.hibernate.util.ReflectHelper.isFinalClass( clazz ); - } - - public static Method getMethod(Class clazz, Method method) { - return org.hibernate.util.ReflectHelper.getMethod( clazz, method ); + static { + Method eq; + Method hash; + try { + eq = extractEqualsMethod( Object.class ); + hash = extractHashCodeMethod( Object.class ); + } + catch ( Exception e ) { + throw new AssertionFailure( "Could not find Object.equals() or Object.hashCode()", e ); + } + OBJECT_EQUALS = eq; + OBJECT_HASHCODE = hash; } /** - * Direct instantiation of ReflectHelper disallowed. + * Disallow instantiation of ReflectHelper. */ private ReflectHelper() { } + /** + * Encapsulation of getting hold of a class's {@link Object#equals equals} method. + * + * @param clazz The class from which to extract the equals method. + * @return The equals method reference + * @throws NoSuchMethodException Should indicate an attempt to extract equals method from interface. + */ + public static Method extractEqualsMethod(Class clazz) throws NoSuchMethodException { + return clazz.getMethod( "equals", SINGLE_OBJECT_PARAM_SIGNATURE ); + } + + /** + * Encapsulation of getting hold of a class's {@link Object#hashCode hashCode} method. + * + * @param clazz The class from which to extract the hashCode method. + * @return The hashCode method reference + * @throws NoSuchMethodException Should indicate an attempt to extract hashCode method from interface. + */ + public static Method extractHashCodeMethod(Class clazz) throws NoSuchMethodException { + return clazz.getMethod( "hashCode", NO_PARAM_SIGNATURE ); + } + + /** + * Determine if the given class defines an {@link Object#equals} override. + * + * @param clazz The class to check + * @return True if clazz defines an equals override. + */ + public static boolean overridesEquals(Class clazz) { + Method equals; + try { + equals = extractEqualsMethod( clazz ); + } + catch ( NoSuchMethodException nsme ) { + return false; //its an interface so we can't really tell anything... + } + return !OBJECT_EQUALS.equals( equals ); + } + + /** + * Determine if the given class defines a {@link Object#hashCode} override. + * + * @param clazz The class to check + * @return True if clazz defines an hashCode override. + */ + public static boolean overridesHashCode(Class clazz) { + Method hashCode; + try { + hashCode = extractHashCodeMethod( clazz ); + } + catch ( NoSuchMethodException nsme ) { + return false; //its an interface so we can't really tell anything... + } + return !OBJECT_HASHCODE.equals( hashCode ); + } + + /** + * Perform resolution of a class name. + *

+ * Here we first check the context classloader, if one, before delegating to + * {@link Class#forName(String, boolean, ClassLoader)} using the caller's classloader + * + * @param name The class name + * @param caller The class from which this call originated (in order to access that class's loader). + * @return The class reference. + * @throws ClassNotFoundException From {@link Class#forName(String, boolean, ClassLoader)}. + */ + public static Class classForName(String name, Class caller) throws ClassNotFoundException { + try { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if ( contextClassLoader != null ) { + return contextClassLoader.loadClass( name ); + } + } + catch ( Throwable ignore ) { + } + return Class.forName( name, true, caller.getClassLoader() ); + } + + /** + * Perform resolution of a class name. + *

+ * Same as {@link #classForName(String, Class)} except that here we delegate to + * {@link Class#forName(String)} if the context classloader lookup is unsuccessful. + * + * @param name The class name + * @return The class reference. + * @throws ClassNotFoundException From {@link Class#forName(String)}. + */ + public static Class classForName(String name) throws ClassNotFoundException { + try { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if ( contextClassLoader != null ) { + return contextClassLoader.loadClass(name); + } + } + catch ( Throwable ignore ) { + } + return Class.forName( name ); + } + + /** + * Is this member publicly accessible. + * + * @param clazz The class which defines the member + * @param member The memeber. + * @return True if the member is publicly accessible, false otherwise. + */ + public static boolean isPublic(Class clazz, Member member) { + return Modifier.isPublic( member.getModifiers() ) && Modifier.isPublic( clazz.getModifiers() ); + } + + /** + * Resolve a constant to its actual value. + * + * @param name The name + * @return The value + */ + public static Object getConstantValue(String name) { + Class clazz; + try { + clazz = classForName( org.hibernate.util.StringHelper.qualifier( name ) ); + } + catch ( Throwable t ) { + return null; + } + try { + return clazz.getField( StringHelper.unqualify( name ) ).get( null ); + } + catch ( Throwable t ) { + return null; + } + } + + /** + * Determine if the given class is declared abstract. + * + * @param clazz The class to check. + * @return True if the class is abstract, false otherwise. + */ + public static boolean isAbstractClass(Class clazz) { + int modifier = clazz.getModifiers(); + return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier); + } + + /** + * Determine is the given class is declared final. + * + * @param clazz The class to check. + * @return True if the class is final, flase otherwise. + */ + public static boolean isFinalClass(Class clazz) { + return Modifier.isFinal( clazz.getModifiers() ); + } + + public static Method getMethod(Class clazz, Method method) { + try { + return clazz.getMethod( method.getName(), method.getParameterTypes() ); + } + catch (Exception e) { + return null; + } + } + }