* 1) Advice must be public
* 2) Advice must have a void return type if not around advice
* 3) Advice must not have any other @AspectJ annotations
+ * 4) After throwing advice must declare the thrown formal
+ * 5) After returning advice must declare the returning formal
*/
private void validateAdvice(MethodDeclaration methodDeclaration) {
if (ajAnnotations.adviceKind != AdviceKind.Around) {
ensureVoidReturnType(methodDeclaration);
}
+
+ if (ajAnnotations.adviceKind == AdviceKind.AfterThrowing) {
+ int[] throwingLocation = new int[2];
+ String thrownFormal = getStringLiteralFor("throwing",ajAnnotations.adviceAnnotation,throwingLocation);
+ if (thrownFormal != null) {
+ Argument[] arguments = methodDeclaration.arguments;
+ if (arguments != null && arguments.length > 0) {
+ Argument lastArgument = arguments[arguments.length - 1];
+ if (!thrownFormal.equals(new String(lastArgument.name))) {
+ methodDeclaration.scope.problemReporter()
+ .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as the last parameter in the advice signature");
+ }
+ } else {
+ methodDeclaration.scope.problemReporter()
+ .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"throwing formal '" + thrownFormal + "' must be declared as the last parameter in the advice signature");
+ }
+ }
+ }
+
+ if (ajAnnotations.adviceKind == AdviceKind.AfterReturning) {
+ int[] throwingLocation = new int[2];
+ String returningFormal = getStringLiteralFor("returning",ajAnnotations.adviceAnnotation,throwingLocation);
+ if (returningFormal != null) {
+ Argument[] arguments = methodDeclaration.arguments;
+ if (arguments != null && arguments.length > 0) {
+ Argument lastArgument = arguments[arguments.length - 1];
+ if (!returningFormal.equals(new String(lastArgument.name))) {
+ methodDeclaration.scope.problemReporter()
+ .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as the last parameter in the advice signature");
+ }
+ } else {
+ methodDeclaration.scope.problemReporter()
+ .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"returning formal '" + returningFormal + "' must be declared as the last parameter in the advice signature");
+ }
+ }
+ }
resolveAndSetPointcut(methodDeclaration, ajAnnotations.adviceAnnotation);
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.patterns.AndPointcut;
import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
import org.aspectj.weaver.patterns.DeclarePrecedence;
boolean hasAtAspectJAnnotationMustReturnVoid = false;
for (int i = 0; i < attributes.length; i++) {
Attribute attribute = attributes[i];
- if (acceptAttribute(attribute)) {
- RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(
- rvs, struct, preResolvedPointcut
- );
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(
- rvs, struct, preResolvedPointcut
- );
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(
- rvs, struct, preResolvedPointcut
- );
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(
- rvs, struct, preResolvedPointcut
- );
- hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(
- rvs, struct, preResolvedPointcut
- );
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
+ try {
+ if (acceptAttribute(attribute)) {
+ RuntimeAnnotations rvs = (RuntimeAnnotations) attribute;
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(
+ rvs, struct, preResolvedPointcut, bMethod
+ );
+ hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(
+ rvs, struct, preResolvedPointcut, bMethod
+ );
+ hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(
+ rvs, struct, preResolvedPointcut
+ );
+ // there can only be one RuntimeVisible bytecode attribute
+ break;
+ }
+ } catch (ReturningFormalNotDeclaredInAdviceSignatureException e) {
+ msgHandler.handleMessage(
+ new Message(
+ WeaverMessages.format(WeaverMessages.RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE,e.getFormalName()),
+ IMessage.ERROR,
+ null,
+ bMethod.getSourceLocation())
+ );
+ } catch (ThrownFormalNotDeclaredInAdviceSignatureException e) {
+ msgHandler.handleMessage(
+ new Message(
+ WeaverMessages.format(WeaverMessages.THROWN_FORMAL_NOT_DECLARED_IN_ADVICE,e.getFormalName()),
+ IMessage.ERROR,
+ null,
+ bMethod.getSourceLocation())
+ ); }
}
hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid;
);
;// go ahead
}
-
-
+
return struct.ajAttributes;
}
* @param struct
* @return true if found
*/
- private static boolean handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ private static boolean handleAfterReturningAnnotation(
+ RuntimeAnnotations runtimeAnnotations,
+ AjAttributeMethodStruct struct,
+ ResolvedPointcutDefinition preResolvedPointcut,
+ BcelMethod owningMethod)
+ throws ReturningFormalNotDeclaredInAdviceSignatureException
+ {
Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION);
if (after != null) {
ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
}
if (annReturned != null) {
returned = annReturned.getValue().stringifyValue();
- if (isNullOrEmpty(returned))
+ if (isNullOrEmpty(returned)) {
returned = null;
+ } else {
+ // check that thrownFormal exists as the last parameter in the advice
+ String[] pNames = owningMethod.getParameterNames();
+ if (pNames == null || pNames.length == 0 || !pNames[pNames.length -1].equals(returned)) {
+ throw new ReturningFormalNotDeclaredInAdviceSignatureException(returned);
+ }
+
+ }
}
// this/target/args binding
* @param struct
* @return true if found
*/
- private static boolean handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) {
+ private static boolean handleAfterThrowingAnnotation(
+ RuntimeAnnotations runtimeAnnotations,
+ AjAttributeMethodStruct struct,
+ ResolvedPointcutDefinition preResolvedPointcut,
+ BcelMethod owningMethod)
+ throws ThrownFormalNotDeclaredInAdviceSignatureException
+ {
Annotation after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION);
if (after != null) {
ElementNameValuePair annValue = getAnnotationElement(after, VALUE);
ElementNameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
- ElementNameValuePair annThrowned = getAnnotationElement(after, THROWING);
+ ElementNameValuePair annThrown = getAnnotationElement(after, THROWING);
// extract the pointcut and throwned type/binding - do some checks
String pointcut = null;
- String throwned = null;
+ String thrownFormal = null;
if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
return false;
reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
return false;
}
- if (annThrowned != null) {
- throwned = annThrowned.getValue().stringifyValue();
- if (isNullOrEmpty(throwned))
- throwned = null;
+ if (annThrown != null) {
+ thrownFormal = annThrown.getValue().stringifyValue();
+ if (isNullOrEmpty(thrownFormal)) {
+ thrownFormal = null;
+ } else {
+ // check that thrownFormal exists as the last parameter in the advice
+ String[] pNames = owningMethod.getParameterNames();
+ if (pNames == null || pNames.length == 0 || !pNames[pNames.length -1].equals(thrownFormal)) {
+ throw new ThrownFormalNotDeclaredInAdviceSignatureException(thrownFormal);
+ }
+ }
}
// this/target/args binding
// exclude the throwned binding from the pointcut binding since it is an extraArg binding
FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
try {
- bindings = (throwned == null ? extractBindings(struct) : extractBindings(struct, throwned));
+ bindings = (thrownFormal == null ? extractBindings(struct) : extractBindings(struct, thrownFormal));
} catch (UnreadableDebugInfoException unreadableDebugInfoException) {
return false;
}
int extraArgument = extractExtraArgument(struct.method);
// return binding
- if (throwned != null) {
+ if (thrownFormal != null) {
extraArgument |= Advice.ExtraArgument;
}
return node;
}
}
+
+ static class ThrownFormalNotDeclaredInAdviceSignatureException extends Exception {
+
+ private String formalName;
+
+ public ThrownFormalNotDeclaredInAdviceSignatureException(String formalName) {
+ this.formalName = formalName;
+ }
+
+ public String getFormalName() { return formalName; }
+ }
+
+ static class ReturningFormalNotDeclaredInAdviceSignatureException extends Exception {
+
+ private String formalName;
+
+ public ReturningFormalNotDeclaredInAdviceSignatureException(String formalName) {
+ this.formalName = formalName;
+ }
+
+ public String getFormalName() { return formalName; }
+ }
}