!!! Annotated Declare Error/Warning

The principles behind declare error/warning, and the example used here is exactly the same as in the [XML|../declare/declare.html] example. But the errors/warnings are declared differently using annotations. 

!! Declaring warnings
To declare a warning, you annotate a field with {{@DeclareWarning}}. This field must be within an {{@Aspect}} or {{@InterceptorDef}} annotated class. The type of the field does not actually matter, though Pointcut has been used in this example. {{DeclareAspect}} is not actually bound to anything and does no interceptions, its sole purpose in this example is as a vessel for the {{@DeclareWarning}} 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;
   }
}}}

*The first {{@DeclareWarning}} annotated field specifies that {{VehicleDAO}} and its subclasses must implement a void noargs save() method. This condition is broken in our example by the fact that {{MotorbikeDAO}} does not do so.
*The second {{@DeclareWarning}} annotated field  specifies that none of the DAO classes can call the Driver constructor. This condition is broken in our example by the fact that {{CarDAO.save()}} tries to create a new {{Driver}} class.
*The third  {{@DeclareWarning}} annotated field specifies that no method on any of the the DAO classes can call the Driver methods. This condition is broken in our example by the fact that {{CarDAO.save()}} tries to call a method on the {{Driver}} class

!! Declaring errors
You declare an error in the same way as a warning, but you use the {{@DeclareError}} annotation instead. Modify {{DeclareAspect}} so that it becomes:

{{{
   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;
   }

}}}

!Run the example compile-time instrumented

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.

!Run the example load-time instrumented

{{{
  $ 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.

!!Declaring errors
If we replace all the {{@DeclareWarning}} occurances with {{@DeclareError}} in {{DeclareAspect}}, an error will get thrown instead
{{{
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;

}
}}}

!!declare-error precompiled
When running precompiled we get:
{{{
$ 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.

!!DeclareError loadtime
When running with loadtime transformations we get:
{{{
$ 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.
