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>