[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