The principles behind declare error/warning, and the example used here is exactly the same as in the XML example. But the errors/warnings are declared differently using annotations.
import org.jboss.aop.DeclareWarning;
@Aspect
public class DeclareAspect
{
@DeclareWarning (expr="class($instanceof{VehicleDAO}) AND !has(public void *->save())", msg="All VehicleDAO subclasses must override the save() method.")
public static Pointcut warning1;
@DeclareWarning (expr="call(Driver->new(..)) AND within(*DAO)", msg="DAO classes should not access the Driver class")
public static Pointcut warning2;
@DeclareWarning (expr="call(* Driver->*(..)) AND withincode(* *DAO->save())", msg="DAO classes should not access the Driver class")
public static Pointcut warning3;
}
import org.jboss.aop.DeclareError;
import org.jboss.aop.Aspect;
import org.jboss.aop.pointcut.Pointcut;
@Aspect
public class DeclareAspect
{
@DeclareError (expr="class($instanceof{VehicleDAO}) AND !has(public void *->save())", msg="All VehicleDAO subclasses must override the save() method.")
public static Pointcut warning1;
@DeclareError (expr="call(Driver->new(..)) AND within(*DAO)", msg="DAO classes should not access the Driver class")
public static Pointcut warning2;
@DeclareError (expr="call(* Driver->*(..)) AND withincode(* *DAO->save())", msg="DAO classes should not access the Driver class")
public static Pointcut warning3;
}
Now if you run the example:
To compile and run:
$ ant
It will generate the following output
Buildfile: build.xml
prepare:
compile:
[aopc] WARNING: declare-warning condition
[aopc] 'call(Driver->new(..)) AND within(*DAO)'
[aopc] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[aopc] DAO classes should not access the Driver class
[aopc] WARNING: declare-warning condition
[aopc] 'call(* Driver->*(..)) AND withincode(* *DAO->save())'
[aopc] was broken for method call:CarDAO.save()V calls Driver.method()V
[aopc] DAO classes should not access the Driver class
[aopc] WARNING: declare-warning condition
[aopc] 'class($instanceof{VehicleDAO}) AND !has(public void *->save())'
[aopc] was broken for class MotorbikeDAO
[aopc] All VehicleDAO subclasses must override the save() method.
run:
[java] ---- Start ----
[java] Car DAO save
BUILD SUCCESSFUL
Note that when using compile time instrumentation the warnings are generated during the aopc phase.
$ ant run.50.instrumented
run.50.instrumented:
[java] ---- Start ----
[java] WARNING: declare-warning condition
[java] 'call(Driver->new(..)) AND within(*DAO)'
[java] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[java] DAO classes should not access the Driver class
[java] WARNING: declare-warning condition
[java] 'call(* Driver->*(..)) AND withincode(* *DAO->save())'
[java] was broken for method call:CarDAO.save()V calls Driver.method()V
[java] DAO classes should not access the Driver class
[java] Car DAO save
[java] WARNING: declare-warning condition
[java] 'class($instanceof{VehicleDAO}) AND !has(public void *->save())'
[java] was broken for class MotorbikeDAO
[java] All VehicleDAO subclasses must override the save() method.
BUILD SUCCESSFUL
Note that now the warnings are displayed when running the application, as the classes are transformed when loaded.
import org.jboss.aop.DeclareError;
@Aspect
public class DeclareAspect
{
@DeclareError (expr="class($instanceof{VehicleDAO}) AND !has(public void *->save())", msg="All VehicleDAO subclasses must override the save() method.")
Pointcut warning1;
@DeclareError (expr="call(Driver->new(..)) AND within(*DAO)", msg="DAO classes should not access the Driver class")
Pointcut warning2;
@DeclareError (expr="call(* Driver->*(..)) AND withincode(* *DAO->save())", msg="DAO classes should not access the Driver class")
Pointcut warning3;
}
$ ant
Buildfile: build.xml
prepare:
compile:
[javac] Compiling 5 source files to C:\cygwin\home\Kab\cvs\jboss-head\aop\docs\examples\annotated-declare
[aopc] ERROR: declare-error condition
[aopc] 'call(Driver->new(..)) AND within(*DAO)'
[aopc] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[aopc] DAO classes should not access the Driver class
[aopc] java.lang.RuntimeException: ERROR: declare-error condition
[aopc] 'call(Driver->new(..)) AND within(*DAO)'
[aopc] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[aopc] DAO classes should not access the Driver class
[aopc] at org.jboss.aop.instrument.DeclareChecker.checkDeclares(DeclareChecker.java:124)
[aopc] at org.jboss.aop.instrument.DeclareChecker.checkDeclares(DeclareChecker.java:57)
[aopc] at org.jboss.aop.instrument.CallerTransformer$CallerExprEditor.edit(CallerTransformer.java:472)
[aopc] at javassist.expr.ExprEditor.doit(ExprEditor.java:136)
[aopc] at javassist.CtBehavior.instrument(CtBehavior.java:362)
[aopc] at org.jboss.aop.instrument.CallerTransformer.applyCallerPointcuts(CallerTransformer.java:69)
[aopc] at org.jboss.aop.instrument.Instrumentor.applyCallerPointcuts(Instrumentor.java:495)
[aopc] at org.jboss.aop.instrument.Instrumentor.transform(Instrumentor.java:562)
[aopc] at org.jboss.aop.AspectManager.translate(AspectManager.java:564)
[aopc] at org.jboss.aop.AspectManager.transform(AspectManager.java:482)
[aopc] at org.jboss.aop.standalone.Compiler.compileFile(Compiler.java:251)
[aopc] at org.jboss.aop.standalone.Compiler.compile(Compiler.java:184)
[aopc] at org.jboss.aop.standalone.Compiler.main(Compiler.java:67)
[aopc] [error] failed to transform: CarDAO.. Do verbose mode if you want full stack trace.
[aopc] Exception in thread "main" java.lang.RuntimeException: failed to transform: CarDAO
[aopc] at org.jboss.aop.instrument.Instrumentor.transform(Instrumentor.java:615)
[aopc] at org.jboss.aop.AspectManager.translate(AspectManager.java:564)
[aopc] at org.jboss.aop.AspectManager.transform(AspectManager.java:482)
[aopc] at org.jboss.aop.standalone.Compiler.compileFile(Compiler.java:251)
[aopc] at org.jboss.aop.standalone.Compiler.compile(Compiler.java:184)
[aopc] at org.jboss.aop.standalone.Compiler.main(Compiler.java:67)
[aopc] Caused by: javassist.CannotCompileException: by java.lang.RuntimeException: ERROR: declare-error condition
[aopc] 'call(Driver->new(..)) AND within(*DAO)'
[aopc] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[aopc] DAO classes should not access the Driver class
[aopc] at org.jboss.aop.instrument.CallerTransformer$CallerExprEditor.edit(CallerTransformer.java:501)
[aopc] at javassist.expr.ExprEditor.doit(ExprEditor.java:136)
[aopc] at javassist.CtBehavior.instrument(CtBehavior.java:362)
[aopc] at org.jboss.aop.instrument.CallerTransformer.applyCallerPointcuts(CallerTransformer.java:69)
[aopc] at org.jboss.aop.instrument.Instrumentor.applyCallerPointcuts(Instrumentor.java:495)
[aopc] at org.jboss.aop.instrument.Instrumentor.transform(Instrumentor.java:562)
[aopc] ... 5 more
See how the compiler stops at the first error and execution stops.
$ ant run.50.instrumented
Buildfile: build.xml
prepare:
compile50standalone:
[javac] Compiling 5 source files to C:\cygwin\home\Kab\cvs\jboss-head\aop\docs\examples\annotated-declare
run.50.instrumented:
[java] ---- Start ----
[java] ERROR: declare-error condition
[java] 'call(Driver->new(..)) AND within(*DAO)'
[java] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[java] DAO classes should not access the Driver class
[java] java.lang.RuntimeException: ERROR: declare-error condition
[java] 'call(Driver->new(..)) AND within(*DAO)'
[java] was broken for constructor call: CarDAO.save()V calls Driver.new()V
[java] DAO classes should not access the Driver class
[java] at org.jboss.aop.instrument.DeclareChecker.checkDeclares(DeclareChecker.java:124)
[java] at org.jboss.aop.instrument.DeclareChecker.checkDeclares(DeclareChecker.java:57)
[java] at org.jboss.aop.instrument.CallerTransformer$CallerExprEditor.edit(CallerTransformer.java:472)
[java] at javassist.expr.ExprEditor.doit(ExprEditor.java:136)
[java] at javassist.CtBehavior.instrument(CtBehavior.java:362)
[java] at org.jboss.aop.instrument.CallerTransformer.applyCallerPointcuts(CallerTransformer.java:69)
[java] at org.jboss.aop.instrument.Instrumentor.applyCallerPointcuts(Instrumentor.java:495)
[java] at org.jboss.aop.instrument.Instrumentor.transform(Instrumentor.java:562)
[java] at org.jboss.aop.AspectManager.translate(AspectManager.java:564)
[java] at org.jboss.aop.AspectManager.transform(AspectManager.java:482)
[java] at org.jboss.aop.standalone.AOPTransformer.transform(AOPTransformer.java:28)
[java] at sun.instrument.TransformerManager.transform(TransformerManager.java:122)
[java] at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:155)
[java] at java.lang.ClassLoader.defineClass1(Native Method)
[java] at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
[java] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
[java] at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
[java] at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
[java] at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
[java] at java.security.AccessController.doPrivileged(Native Method)
[java] at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
[java] at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
[java] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
[java] at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
[java] at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
[java] at Driver.createVehicles(Driver.java:24)
[java] at Driver.main(Driver.java:19)
[java] [error] failed to transform: CarDAO.. Do verbose mode if you want full stack trace.
[java] Car DAO save
[java] [error] failed to transform: MotorbikeDAO.. Do verbose mode if you want full stack trace.
Again you can see how the first broken condition causes execution to stop.