[jboss-cvs] JBossAS SVN: r58715 - projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Nov 28 20:02:34 EST 2006


Author: flaviarnn
Date: 2006-11-28 20:02:27 -0500 (Tue, 28 Nov 2006)
New Revision: 58715

Modified:
   projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceInfo.java
   projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceMethodFactory.java
   projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AnnotatedParameterAdviceInfo.java
Log:
[JBAOP-37] Solved bug on best match.

Modified: projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceInfo.java
===================================================================
--- projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceInfo.java	2006-11-29 00:39:00 UTC (rev 58714)
+++ projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceInfo.java	2006-11-29 01:02:27 UTC (rev 58715)
@@ -34,60 +34,161 @@
    }
    
    /**
-    * Indicates the distance between <code>class</code> and <code>lookingFor</code>
-    * in the class hierarchy.
+    * Returns the assignability degree from <code>fromType</code> to </code>toType</code>. 
+    * <p>
+    * The assignability degree is the distance in class and interface hierarchy between
+    * <code>fromType</code> and </code>toType</code>. If <code>toType</code> is an
+    * interface implemented by <code>fromType</code>, then the degree is 1. Otherwise,
+    * the degree is exactly the number of hierarchical levels between <code>fromType
+    * </code> and <code>toType</code>.
     * 
-    * @param clazz      the type of an annotated parameter
-    * @param lookingFor the expected type of the parameter
-    * @return {@link AdviceMethodFactory#NOT_ASSIGNABLE_DEGREE if a value of type <code>
-    *         lookingFor</code> can't be assigned to a parameter of type <code>class
-    *         </code>; the distance between <code>class </code> and <code>lookingFor
-    *         </code> otherwise.
+    * @param fromType the type from which <code>toType</code> is supposedly assignable.
+    * @param toType   the type to which <code>fromType</code> can be converted without
+    *                 type casting.
+    * @return {@link AdviceMethodFactory#NOT_ASSIGNABLE_DEGREE if <code>toType</code> is
+    *         not assignable from <code>fromType</code>; the hierarchical distance between
+    *         <code>fromType</code> and <code>toType</code> otherwise.
+    *         
+    * @see java.lang.Class#isAssignableFrom(Class)
     */
-   protected short matchClass(Class clazz, Class lookingFor)
+   protected short getAssignabilityDegree(Class<?> fromType, Class<?> toType)
    {
-      return matchClass(clazz, lookingFor, (short) 0);
+      // they're the same
+      if (fromType == toType)
+      {
+         return 0;
+      }
+      if (toType.isInterface())
+      {
+         if (fromType.isInterface())
+         {
+            // assignability degree on interface inheritance
+            return getInterfaceInheritanceAD(fromType, toType, (short) 0);
+         }
+         else
+         {
+            // assignability degree on interface implementation
+            return getImplementationAD(fromType, toType);
+         }
+      }
+      if (fromType.isInterface())
+      {
+         // you can't get to a class from an interface
+         return AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
+      }
+      // assignability degree on class inheritance
+      return getClassInheritanceAD(fromType.getSuperclass(), toType, (short) 1);
    }
    
    /**
-    * Recursive method that return the distance between <code>wanted</code> and <code>
-    * candidate</code> in the class hierarchy.
+    * Returns the assignability degree between <code>fromClassType</code> and <code>
+    * toInterfaceType</code>.
     * 
-    * @param wanted      the expected type of the parameter
-    * @param candidate   the current type being matched
-    * @param matchDegree the current matchDegree
-    * @return -1 if a value of type <code>lookingFor</code> can't be assigned to
-    *         a parameter of type <code>class</code>; the distance between <code>class
-    *         </code> and <code>lookingFor</code> otherwise.
+    * @param fromClassType   a class type that supposedly implements <code>
+    *                        toInterfaceType</code>
+    * @param toInterfaceType an interface type that is supposedly implemented by <code>
+    *                        fromClassType</code>
+    * @return {@link AdviceMethodFactory#NOT_ASSIGNABLE_DEGREE} if <code>fromClassType
+    *         </code> does not implement <code>toInterfaceType</code>; otherwise, if
+    *         <code>fromType</code> implements a subinterface of <code>toInterfaceType
+    *         </code>, returns 1 + the assignability degree between this subinterface and
+    *         <code>toType</code>; otherwhise, returns 1.
+    *         
     */
-   private short matchClass(Class wanted, Class candidate, short matchDegree)
+   private short getImplementationAD(Class<?> fromClassType, Class<?> toInterfaceType)
    {
-      if (candidate == null)
+      if (fromClassType == null)
       {
          return AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
       }
-      if (candidate.equals(wanted))
+      
+      Class[] interfaces = fromClassType.getInterfaces();
+      for (int i = 0 ; i < interfaces.length ; i++)
       {
-         return matchDegree;
+         if(interfaces[i] == toInterfaceType)
+         {
+            return 1;
+         }
       }
-
-      matchDegree++;
-      
-      Class[] interfaces = candidate.getInterfaces();
+      short currentDegree = AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
       for (int i = 0 ; i < interfaces.length ; i++)
       {
-         if (matchClass(wanted, interfaces[i], matchDegree) > 0)
+         currentDegree = (short) Math.min(getInterfaceInheritanceAD(interfaces[i],
+               toInterfaceType, (short) 1), currentDegree);
+      }
+      if (currentDegree == AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE)
+      {
+         return getImplementationAD(fromClassType.getSuperclass(), toInterfaceType);
+      }
+      return currentDegree;
+   }
+   
+   /**
+    * Recursive method that returns the assignability degree on an interface inheritance.
+    * 
+    * @param fromInterfaceType  the interface that supposedly inherits (directly or
+    *                           indirectly <code>toInterfaceType</code>.
+    * @param toInterfaceType    the interface which is supposedly assignable from <code>
+    *                           fromInterfaceType</code>. The type <code>
+    *                           toInterfaceType</code> is not the same as <code>
+    *                           fromInterfaceType</code>.
+    * @param currentDegree      the current assignability degree
+    * @return                   {@link AdviceMethodFactory#NOT_ASSIGNABLE_DEGREE} if
+    *                           <code>toInterfaceType</code> is not assignable from <code>
+    *                           fromInterfaceType</code>; <code>currentDegree + </code>
+    *                           the assignability degree from <code>fromInterfaceType
+    *                           </code> to <code>toInterfaceType</code>.
+    */
+   public short getInterfaceInheritanceAD(Class<?> fromInterfaceType,
+         Class<?> toInterfaceType, short currentDegree)
+   {
+      Class[] interfaces = fromInterfaceType.getInterfaces();
+      currentDegree ++;
+      for (int i = 0; i < interfaces.length; i++)
+      {
+         if(interfaces[i] == toInterfaceType)
          {
-            return matchDegree;
+            return currentDegree;
          }
       }
-      
-      if (matchClass(wanted, candidate.getSuperclass(), matchDegree) > 0)
+      short bestDegree = AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
+      for (int i = 0; i < interfaces.length; i++)
       {
-         return matchDegree;
+         bestDegree = (short) Math.min(getInterfaceInheritanceAD(interfaces[i],
+               toInterfaceType, currentDegree), bestDegree);
       }
-      return AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
+      return bestDegree;
    }
+   
+   /**
+    * Recursive method that returns the assignability degree on an class inheritance.
+    * 
+    * @param fromClassType  the class that supposedly inherits (directly or
+    *                       indirectly <code>toClassType</code>.
+    * @param toClassType    the class which is supposedly assignable from <code>
+    *                       fromInterfaceType</code>. The type <code>toClassType</code> is
+    *                       not the same as <code>fromClassType</code>.
+    * @param currentDegree  the current assignability degree
+    * @return               {@link AdviceMethodFactory#NOT_ASSIGNABLE_DEGREE} if <code>
+    *                       toClassType</code> is not assignable from <code>fromClassType
+    *                       </code>; <code>currentDegree + </code> the assignability
+    *                       degree from <code>fromClassType</code> to <code>toClassType
+    *                       </code>.
+    */
+   private short getClassInheritanceAD(Class<?> fromClassType, Class<?> toClassType,
+         short currentDegree)
+   {
+      if (fromClassType == null)
+      {
+         return AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
+      }
+      if (fromClassType == toClassType)
+      {
+         return currentDegree;
+      }
+      return getClassInheritanceAD(fromClassType.getSuperclass(), toClassType,
+            ++currentDegree);
+   }
 
    /**
     * Returns the distance in hierarchy between the annotated parameter identified by
@@ -106,17 +207,17 @@
       {
          return AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE;
       }
-      short degree = this.matchClass(properties.getJoinpointReturnType(), returnType);
+      short degree = this.getAssignabilityDegree(returnType,
+            properties.getJoinpointReturnType());
       if (degree == AdviceMethodFactory.NOT_ASSIGNABLE_DEGREE)
       {
          // return type is Object.class and join point return type is not
          // Object is worse than join point return type, but better than -1
-         return AdviceMethodFactory.MAX_ASSIGNABLE_DEGREE;
+         return AdviceMethodFactory.MAX_DEGREE;
       }
       return degree;
    }
 
-   
    /**
     * Returns the rank of this advice.
     * @return the rank value

Modified: projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceMethodFactory.java
===================================================================
--- projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceMethodFactory.java	2006-11-29 00:39:00 UTC (rev 58714)
+++ projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AdviceMethodFactory.java	2006-11-29 01:02:27 UTC (rev 58715)
@@ -59,7 +59,7 @@
    /**
     * Factory that selects advice methods for <i>after</i> interception.
     */
-   public static final       AdviceMethodFactory AFTER = new AdviceMethodFactory (null,
+   public static final AdviceMethodFactory AFTER = new AdviceMethodFactory (null,
          new ParameterAnnotationRule[]{ParameterAnnotationRule.JOIN_POINT,
          ParameterAnnotationRule.RETURN, ParameterAnnotationRule.ARGS,
          ParameterAnnotationRule.ARG}, new int[][]{{2, 3}}, ReturnType.ANY);
@@ -150,7 +150,7 @@
                   public short getAssignabilityDegree(int typeIndex,
                         AdviceMethodProperties properties)
                   {
-                     return matchClass(parameterTypes[0], properties.getInvocationType());
+                     return getAssignabilityDegree(parameterTypes[0], properties.getInvocationType());
                   }
                   
                   public void assignAdviceInfo(AdviceMethodProperties properties)
@@ -168,7 +168,7 @@
 
    static StringBuffer adviceMatchingMessage;
    static final short NOT_ASSIGNABLE_DEGREE = Short.MAX_VALUE;
-   static final short MAX_ASSIGNABLE_DEGREE = NOT_ASSIGNABLE_DEGREE - 1;
+   static final short MAX_DEGREE = NOT_ASSIGNABLE_DEGREE - 1;
    
    /**
     * Method that returns log information about the last matching process executed.
@@ -182,7 +182,7 @@
       return message;
    }
    
-   private ReturnType adviceReturn;
+   private ReturnType returnType;
    private AdviceSignatureRule adviceSignatureRule;
    private ParameterAnnotationRule[] rules;
    private int[][] mutuallyExclusive;
@@ -196,17 +196,17 @@
     * @param rules               the parameter annotation rules that can be used by
     *                            this factory on the advice method matching.
     * @param mutuallyExclusive   collection of the rules that are mutually exclusive
-    * @param canReturn          indicates whether the queried advice methods can return
+    * @param returnType          indicates whether the queried advice methods can return
     *                            a value to overwrite the join point execution result.
     */
    private AdviceMethodFactory(AdviceSignatureRule adviceSignatureRule,
          ParameterAnnotationRule[] rules, int[][] mutuallyExclusive,
-         ReturnType adviceReturn)
+         ReturnType returnType)
    {
       this.adviceSignatureRule = adviceSignatureRule;
       this.rules = rules;
       this.mutuallyExclusive = mutuallyExclusive;
-      this.adviceReturn = adviceReturn;
+      this.returnType = returnType;
    }
    
    /**
@@ -297,7 +297,7 @@
       while (iterator.hasNext())
       {
          AdviceInfo advice = iterator.next();
-         if (advice.validate(properties, mutuallyExclusive, adviceReturn))
+         if (advice.validate(properties, mutuallyExclusive, returnType))
          {
             bestAdvice = advice;
             break;
@@ -323,7 +323,7 @@
          AdviceInfo advice = iterator.next();
          if (advice.getRank() == bestAdvice.getRank())
          {
-            if (!advice.validate(properties, mutuallyExclusive, adviceReturn))
+            if (!advice.validate(properties, mutuallyExclusive, returnType))
             {
                iterator.remove();
             }
@@ -387,38 +387,6 @@
                iterator.remove();
             }
          }
-            /*
-            // advice has no annotation of type i
-            if (currentDegree == -1)
-            {
-               if (bestDegree != -1)
-               {
-                  // this advice is worst than the best current match
-                  greatestRank.remove(currentAdvice);
-               }
-               else if (bestAdvice == null)
-               {
-                  // current best advice has no parameter with this annotation
-                  bestAdvice = currentAdvice;
-               }
-            }
-            // this advice is better than current best match
-            else if (bestDegree == -1 || currentDegree < bestDegree)
-            {
-               if (bestAdvice != null)
-               {
-                  // the old best advice is gone
-                  greatestRank.remove(bestAdvice);
-               }
-               bestDegree = currentDegree;
-               bestAdvice = currentAdvice;
-            }
-            // this advice is not as good as current best match
-            else if (currentDegree > bestDegree)
-            {
-               greatestRank.remove(currentAdvice);
-            }
-         }*/
          // found the best
          if (greatestRank.size() - removeList.size() == 1)
          {
@@ -430,16 +398,21 @@
          bestAdvice = null;
          bestDegree = NOT_ASSIGNABLE_DEGREE;
       }
-      for (AdviceInfo currentAdvice: greatestRank)
+      if (returnType == ReturnType.ANY || returnType == ReturnType.NOT_VOID)
       {
-         int currentDegree =  currentAdvice.getReturnAssignabilityDegree(properties);
-         if (currentDegree < bestDegree)
+         for (AdviceInfo currentAdvice: greatestRank)
          {
-            bestAdvice = currentAdvice;
+            int currentDegree =  currentAdvice.getReturnAssignabilityDegree(properties);
+            if (currentDegree < bestDegree)
+            {
+               bestAdvice = currentAdvice;
+            }
          }
+         //in case of two or more advices with the same match degree, pick any one of them
+         return bestAdvice;
       }
-      // in case of two or more advices with the same match degree, pick any one of them
-      return bestAdvice;
+      // we have more than one best advice; return any one of them
+      return greatestRank.iterator().next();
    }
    
    /**

Modified: projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AnnotatedParameterAdviceInfo.java
===================================================================
--- projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AnnotatedParameterAdviceInfo.java	2006-11-29 00:39:00 UTC (rev 58714)
+++ projects/aop/trunk/aop/src/main/org/jboss/aop/advice/annotation/AnnotatedParameterAdviceInfo.java	2006-11-29 01:02:27 UTC (rev 58715)
@@ -268,7 +268,7 @@
    {
       if (AspectManager.verbose)
       {
-         throw new ParameterAnnotationRuleException("[warn] -parameter " + i  +
+         throw new ParameterAnnotationRuleException("\n[warn] -parameter " + i  +
                " of method " + method +  " is not annotated");
       }
       else
@@ -290,7 +290,7 @@
     *                              processed before a multi-annotated parameter was found
     * @throws MultipleAdviceInfoException
     */
-   private void throwMAIException(Annotation[][] paramAnnotations,
+   private final void throwMAIException(Annotation[][] paramAnnotations,
       int[] singleAnnotations, int singleAnnotationsSize)
       throws MultipleAdviceInfoException
    {
@@ -476,7 +476,7 @@
          {
             if (AspectManager.verbose)
             {
-               throw new ParameterAnnotationRuleException("[warn] - found more than "
+               throw new ParameterAnnotationRuleException("\n[warn] - found more than "
                      + "one occurence of " + rule.getAnnotation().getName() +
                      " on parameters of advice" + method);  
             }
@@ -516,8 +516,9 @@
          {
             return -1;
          }
-         return matchClass(method.getParameterTypes()[this.index],
-               (Class) rule.getAssignableFrom(properties));
+         return AnnotatedParameterAdviceInfo.this.getAssignabilityDegree(
+               (Class) rule.getAssignableFrom(properties),
+               method.getParameterTypes()[this.index]);
       }
       
       public final void assignParameterInfo(int[] args)
@@ -624,8 +625,9 @@
          short level = 0;
          for (int i = 0; i < indexesLength; i++)
          {
-            level += matchClass(method.getParameterTypes()[this.indexes[i][0]],
-                  expectedTypes[this.indexes[i][1]]);
+            level += AnnotatedParameterAdviceInfo.this.getAssignabilityDegree(
+                  expectedTypes[this.indexes[i][1]],
+                  method.getParameterTypes()[this.indexes[i][0]]);
          }
          return level; 
       }




More information about the jboss-cvs-commits mailing list