You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by si...@apache.org on 2012/01/29 17:16:51 UTC
svn commit: r1237323 -
/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/AccessibleObjectsRegistry.java
Author: simonetripodi
Date: Sun Jan 29 16:16:51 2012
New Revision: 1237323
URL: http://svn.apache.org/viewvc?rev=1237323&view=rev
Log:
centralized all the logic in the abstract implementation
Modified:
commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/AccessibleObjectsRegistry.java
Modified: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/AccessibleObjectsRegistry.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/AccessibleObjectsRegistry.java?rev=1237323&r1=1237322&r2=1237323&view=diff
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/AccessibleObjectsRegistry.java (original)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/AccessibleObjectsRegistry.java Sun Jan 29 16:16:51 2012
@@ -28,8 +28,8 @@ import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Map;
@@ -37,7 +37,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-abstract class AccessibleObjectsRegistry<AO extends AccessibleObject>
+abstract class AccessibleObjectsRegistry<AO extends AccessibleObject & Member>
{
private static final AccessibleObjectsRegistry<Constructor<?>> CONSTRUCTORS_REGISTRY = new ConstructorsRegistry();
@@ -67,27 +67,89 @@ abstract class AccessibleObjectsRegistry
return get( exact, type, null, parameterTypes );
}
- public final AO get( boolean exact, Class<?> type, String methodName, Class<?>... parameterTypes )
+ public final AO get( boolean exact, Class<?> type, String name, Class<?>... parameterTypes )
{
- AccessibleObjectDescriptor key = new AccessibleObjectDescriptor( exact, type, methodName, parameterTypes );
+ AccessibleObjectDescriptor key = new AccessibleObjectDescriptor( exact, type, name, parameterTypes );
final Lock lock = new ReentrantLock();
lock.lock();
try
{
- Reference<AO> methodReference = cache.get( key );
- if ( methodReference != null )
+ Reference<AO> accessibleObjectReference = cache.get( key );
+ if ( accessibleObjectReference != null )
{
- return methodReference.get();
+ return accessibleObjectReference.get();
}
- AO accessibleObject = resolve( exact, type, methodName, parameterTypes );
- if ( accessibleObject != null )
+ // see if we can find the accessible object directly
+ // most of the time this works and it's much faster
+ try
{
- accessibleObject = makeAccessible( accessibleObject );
+ AO accessibleObject = resolveDirectly( type, name, parameterTypes );
+ if ( exact || accessibleObject != null )
+ {
+ return makeAccessible( accessibleObject );
+ }
}
- cache.put( key, new WeakReference<AO>( accessibleObject ) );
- return accessibleObject;
+ catch ( NoSuchMethodException e )
+ {
+ /* SWALLOW */
+ if ( exact )
+ {
+ return null;
+ }
+ }
+
+ // start calculating the best matching
+
+ int paramSize = parameterTypes.length;
+ AO bestMatch = null;
+ AO[] accessibleObjectsArray = getAccessibleObjectsArray( type );
+ float bestMatchCost = Float.MAX_VALUE;
+ float myCost = Float.MAX_VALUE;
+ for ( int i = 0, size = accessibleObjectsArray.length; i < size; i++ )
+ {
+ if ( matches( accessibleObjectsArray[i], name ) )
+ {
+ // compare parameters
+ Class<?>[] methodsParams = getParameterTypes( accessibleObjectsArray[i] );
+ int methodParamSize = methodsParams.length;
+ if ( methodParamSize == paramSize )
+ {
+ boolean match = true;
+ for ( int n = 0; n < methodParamSize; n++ )
+ {
+ if ( !isAssignmentCompatible( methodsParams[n], parameterTypes[n] ) )
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if ( match )
+ {
+ // get accessible version of method
+ AO current = resolveAccessible( type, accessibleObjectsArray[i] );
+ if ( current != null )
+ {
+ myCost = getTotalTransformationCost( parameterTypes, getParameterTypes( current ) );
+ if ( myCost < bestMatchCost )
+ {
+ bestMatch = current;
+ bestMatchCost = myCost;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( bestMatch != null )
+ {
+ bestMatch = makeAccessible( bestMatch );
+ }
+ cache.put( key, new WeakReference<AO>( bestMatch ) );
+ return bestMatch;
}
finally
{
@@ -95,6 +157,85 @@ abstract class AccessibleObjectsRegistry
}
}
+ protected abstract AO resolveDirectly( Class<?> type, String name, Class<?>... parameterTypes )
+ throws NoSuchMethodException;
+
+ protected abstract AO[] getAccessibleObjectsArray( Class<?> type );
+
+ protected abstract boolean matches( AO accessibleObject, String name );
+
+ protected abstract Class<?>[] getParameterTypes( AO accessibleObject );
+
+ protected abstract AO resolveAccessible( Class<?> type, AO accessibleObject );
+
+ /**
+ * Returns the sum of the object transformation cost for each class in the source
+ * argument list.
+ * @param srcArgs The source arguments
+ * @param destArgs The destination arguments
+ * @return The total transformation cost
+ */
+ private static float getTotalTransformationCost( Class<?>[] srcArgs, Class<?>[] destArgs )
+ {
+ float totalCost = 0.0f;
+ for ( int i = 0; i < srcArgs.length; i++ )
+ {
+ Class<?> srcClass, destClass;
+ srcClass = srcArgs[i];
+ destClass = destArgs[i];
+ totalCost += getObjectTransformationCost( srcClass, destClass );
+ }
+ return totalCost;
+ }
+
+ /**
+ * Gets the number of steps required needed to turn the source class into the
+ * destination class. This represents the number of steps in the object hierarchy
+ * graph.
+ *
+ * @param srcClass The source class
+ * @param destClass The destination class
+ * @return The cost of transforming an object
+ */
+ private static float getObjectTransformationCost( Class<?> srcClass, Class<?> destClass )
+ {
+ float cost = 0.0f;
+ while ( srcClass != null && !destClass.equals( srcClass ) )
+ {
+ if ( destClass.isPrimitive() )
+ {
+ Class<?> destClassWrapperClazz = getPrimitiveWrapper( destClass );
+ if ( destClassWrapperClazz != null && destClassWrapperClazz.equals( srcClass ) )
+ {
+ cost += 0.25f;
+ break;
+ }
+ }
+ if ( destClass.isInterface() && isAssignmentCompatible( destClass, srcClass ) )
+ {
+ // slight penalty for interface match.
+ // we still want an exact match to override an interface match, but
+ // an interface match should override anything where we have to get a
+ // superclass.
+ cost += 0.25f;
+ break;
+ }
+ cost++;
+ srcClass = srcClass.getSuperclass();
+ }
+
+ /*
+ * If the destination class is null, we've travelled all the way up to an Object match. We'll penalize this
+ * by adding 1.5 to the cost.
+ */
+ if ( srcClass == null )
+ {
+ cost += 1.5f;
+ }
+
+ return cost;
+ }
+
private AO makeAccessible( AO accessibleObject )
{
PrivilegedAction<AO> action = new MakeAccessiblePrivilegedAction<AO>( accessibleObject );
@@ -105,8 +246,6 @@ abstract class AccessibleObjectsRegistry
return action.run();
}
- protected abstract AO resolve( boolean exact, Class<?> cls, String methodName, Class<?>... paramTypes );
-
/**
* Constructors registry implementation.
*/
@@ -114,87 +253,48 @@ abstract class AccessibleObjectsRegistry
{
@Override
- protected Constructor<?> resolve( boolean exact, Class<?> type, String methodName, Class<?>...parameterTypes )
+ protected Constructor<?> resolveDirectly( Class<?> type, String name, Class<?>...parameterTypes )
+ throws NoSuchMethodException
{
- // see if we can find the method directly
- // most of the time this works and it's much faster
- try
- {
- Constructor<?> ctor = type.getConstructor( parameterTypes );
- if ( exact || ctor != null )
- {
- return getAccessibleConstructor( ctor );
- }
- }
- catch ( NoSuchMethodException e )
- {
- /* SWALLOW */
- if ( exact )
- {
- return null;
- }
- }
-
- // search through all methods
- int paramSize = parameterTypes.length;
+ return type.getConstructor( parameterTypes );
+ }
- for ( Constructor<?> ctor : type.getConstructors() )
- {
- // compare parameters
- Class<?>[] ctorParams = ctor.getParameterTypes();
- int ctorParamSize = ctorParams.length;
- if ( ctorParamSize == paramSize )
- {
- boolean match = true;
- for ( int n = 0; n < ctorParamSize; n++ )
- {
- if ( !isAssignmentCompatible( ctorParams[n], parameterTypes[n] ) )
- {
- match = false;
- break;
- }
- }
+ @Override
+ protected Constructor<?>[] getAccessibleObjectsArray( Class<?> type )
+ {
+ return type.getConstructors();
+ }
- if ( match )
- {
- // get accessible version of method
- ctor = getAccessibleConstructor( ctor );
- if ( ctor != null )
- {
- return ctor;
- }
- }
- }
- }
+ @Override
+ protected boolean matches( Constructor<?> accessibleObject, String name )
+ {
+ return true;
+ }
- return null;
+ @Override
+ protected Class<?>[] getParameterTypes( Constructor<?> accessibleObject )
+ {
+ return accessibleObject.getParameterTypes();
}
- /**
- * Returns accessible version of the given constructor.
- * @param ctor prototype constructor object.
- * @return <code>null</code> if accessible constructor can not be found.
- * @see java.lang.SecurityManager
- */
- private static <T> Constructor<T> getAccessibleConstructor( Constructor<T> ctor )
+ @Override
+ protected Constructor<?> resolveAccessible( Class<?> type, Constructor<?> accessibleObject )
{
- // Make sure we have a method to check
- if ( ctor == null )
+ if ( accessibleObject == null )
{
- return ( null );
+ return null;
}
- // If the requested method is not public we cannot call it
- if ( !isPublic( ctor.getModifiers() ) )
+ if ( !isPublic( accessibleObject.getModifiers() ) )
{
- return ( null );
+ return null;
}
// If the declaring class is public, we are done
- Class<T> beanClass = ctor.getDeclaringClass();
+ Class<?> beanClass = accessibleObject.getDeclaringClass();
if ( isPublic( beanClass.getModifiers() ) )
{
- return ctor;
+ return accessibleObject;
}
// what else can we do?
@@ -210,108 +310,57 @@ abstract class AccessibleObjectsRegistry
{
@Override
- public Method resolve( boolean exact, Class<?> clazz, String methodName, Class<?>...parameterTypes )
+ protected Method resolveDirectly( Class<?> type, String name, Class<?>...parameterTypes )
+ throws NoSuchMethodException
{
- // see if we can find the method directly
- // most of the time this works and it's much faster
- try
- {
- Method method = clazz.getMethod(methodName, parameterTypes);
- if ( exact || method != null )
- {
- return method;
- }
- }
- catch ( NoSuchMethodException e )
- {
- /* SWALLOW */
- if ( exact )
- {
- return null;
- }
- }
-
- // search through all methods
- int paramSize = parameterTypes.length;
- Method bestMatch = null;
- Method[] methods = clazz.getMethods();
- float bestMatchCost = Float.MAX_VALUE;
- float myCost = Float.MAX_VALUE;
- for ( int i = 0, size = methods.length; i < size; i++ )
- {
- if ( methods[i].getName().equals( methodName ) )
- {
- // compare parameters
- Class<?>[] methodsParams = methods[i].getParameterTypes();
- int methodParamSize = methodsParams.length;
- if ( methodParamSize == paramSize )
- {
- boolean match = true;
- for ( int n = 0; n < methodParamSize; n++ )
- {
+ return type.getMethod( name, parameterTypes );
+ }
- if ( !isAssignmentCompatible( methodsParams[n], parameterTypes[n] ) )
- {
- match = false;
- break;
- }
- }
+ @Override
+ protected Method[] getAccessibleObjectsArray( Class<?> type )
+ {
+ return type.getMethods();
+ }
- if ( match )
- {
- // get accessible version of method
- Method method = getAccessibleMethod( clazz, methods[i] );
- if ( method != null )
- {
- myCost = getTotalTransformationCost( parameterTypes, method.getParameterTypes() );
- if ( myCost < bestMatchCost )
- {
- bestMatch = method;
- bestMatchCost = myCost;
- }
- }
- }
- }
- }
- }
+ @Override
+ protected boolean matches( Method accessibleObject, String name )
+ {
+ return name.equals( accessibleObject.getName() );
+ }
- return bestMatch;
+ @Override
+ protected Class<?>[] getParameterTypes( Method accessibleObject )
+ {
+ return accessibleObject.getParameterTypes();
}
- /**
- * <p>Return an accessible method (that is, one that can be invoked via
- * reflection) that implements the specified Method. If no such method
- * can be found, return <code>null</code>.</p>
- *
- * @param clazz The class of the object
- * @param method The method that we wish to call
- * @return The accessible method
- */
- private static Method getAccessibleMethod(Class<?> clazz, Method method) {
+ @Override
+ protected Method resolveAccessible( Class<?> type, Method method )
+ {
// Make sure we have a method to check
if ( method == null )
{
- return ( null );
+ return null;
}
// If the requested method is not public we cannot call it
- if ( !Modifier.isPublic( method.getModifiers() ) )
+ if ( !isPublic( method.getModifiers() ) )
{
- return ( null );
+ return null;
}
- if ( clazz == null )
+ if ( type == null )
{
- clazz = method.getDeclaringClass();
+ type = method.getDeclaringClass();
}
else
{
- checkArgument( method.getDeclaringClass().isAssignableFrom( clazz ),
- "%s is not assignable from ", clazz.getName(), method.getDeclaringClass().getName() );
+ checkArgument( method.getDeclaringClass().isAssignableFrom( type ),
+ "%s is not assignable from ", type.getName(), method.getDeclaringClass().getName() );
}
// If the class is public, we are done
- if ( isPublic( clazz.getModifiers() ) )
+ if ( isPublic( type.getModifiers() ) )
{
return method;
}
@@ -320,86 +369,18 @@ abstract class AccessibleObjectsRegistry
Class<?>[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
- method = getAccessibleMethodFromInterfaceNest( clazz, methodName, parameterTypes );
+ method = getAccessibleMethodFromInterfaceNest( type, methodName, parameterTypes );
// Check the superclass chain
if ( method == null )
{
- method = getAccessibleMethodFromSuperclass( clazz, methodName, parameterTypes );
+ method = getAccessibleMethodFromSuperclass( type, methodName, parameterTypes );
}
return method;
}
/**
- * Returns the sum of the object transformation cost for each class in the source
- * argument list.
- * @param srcArgs The source arguments
- * @param destArgs The destination arguments
- * @return The total transformation cost
- */
- private static float getTotalTransformationCost( Class<?>[] srcArgs, Class<?>[] destArgs )
- {
- float totalCost = 0.0f;
- for ( int i = 0; i < srcArgs.length; i++ )
- {
- Class<?> srcClass, destClass;
- srcClass = srcArgs[i];
- destClass = destArgs[i];
- totalCost += getObjectTransformationCost( srcClass, destClass );
- }
- return totalCost;
- }
-
- /**
- * Gets the number of steps required needed to turn the source class into the
- * destination class. This represents the number of steps in the object hierarchy
- * graph.
- *
- * @param srcClass The source class
- * @param destClass The destination class
- * @return The cost of transforming an object
- */
- private static float getObjectTransformationCost( Class<?> srcClass, Class<?> destClass )
- {
- float cost = 0.0f;
- while ( srcClass != null && !destClass.equals( srcClass ) )
- {
- if ( destClass.isPrimitive() )
- {
- Class<?> destClassWrapperClazz = getPrimitiveWrapper( destClass );
- if ( destClassWrapperClazz != null && destClassWrapperClazz.equals( srcClass ) )
- {
- cost += 0.25f;
- break;
- }
- }
- if ( destClass.isInterface() && isAssignmentCompatible( destClass, srcClass ) )
- {
- // slight penalty for interface match.
- // we still want an exact match to override an interface match, but
- // an interface match should override anything where we have to get a
- // superclass.
- cost += 0.25f;
- break;
- }
- cost++;
- srcClass = srcClass.getSuperclass();
- }
-
- /*
- * If the destination class is null, we've travelled all the way up to an Object match. We'll penalize this
- * by adding 1.5 to the cost.
- */
- if ( srcClass == null )
- {
- cost += 1.5f;
- }
-
- return cost;
- }
-
- /**
* <p>Return an accessible method (that is, one that can be invoked via
* reflection) by scanning through the superclasses. If no such method
* can be found, return <code>null</code>.</p>