Argument Checking Aspect

Another interesting aspect that applies to several scenarios is to check the validity of the arguments of a method. This is a common practice in the so called “Design by Contract” methodology and as it is a crosscutting concern, it is subject to be implemented as an aspect. In this section we will see how to implement an argument checking aspect using two different approaches: with a metaobject and with link's restrictions.

Using a Metaobject

In our example, it would be interesting if we could check that the argument received by the get method is a non-negative integer. To do so, we will use a metaobject that will check the argument and it will not proceed (it will throw an exception) if the argument is not valid.

Let us define the hookset, metaobject definition and behavioral link.

Here is the hookset:

Hookset theHookset = new PrimitiveHookset(
        MsgReceive.class,
        new NameCS("reflex.examples.fibonacci.app.Fibonacci"),
        new NameOS("get")
);

For this example, we have changed the OperationSelector, as we want to match only the method get (and not the main method). Here we use another utility class: NameOS that selects operations that have the given name, in our case get.

The code for the metaobject definition is:

MODefinition theMO = new MODefinition.SharedMO(new PositiveNumberChecker());

Here we use a PositiveNumberChecker class (in charge of checking the argument) that is defined this way:

public static class PositiveNumberChecker{
 
    public void check(int anArgument){
        if (anArgument < 0){
            throw new IllegalArgumentException("The argument must be " + 
            "non-negative:" + anArgument);
        }
   }
}

As you can see, there is just one method called check that does the argument checking. In order to make this method be called, we should use an appropriate call descriptor. Here is the behavioral link definition and configuration:

BLink theLink = Links.get(theHookset, theMO);
theLink.setControl(Control.BEFORE);
theLink.setCall(Control.BEFORE, PositiveNumberChecker.class.getName(), "check",
                new StdParameters.IndexedArgument(0)));

In the code above we set the control of the link as before: we want to check the parameter before any other statement is executed. Also, we specified that the call that should be done over the metaobject is check with one parameter: the first parameter of the original method being executed (get in our case). To access the first parameter we use another utility class: StdParameters.IndexedArgument that is a parameter that returns the indexed argument we specify in the constructor (in our case the first one, represented by 0).

The complete code of the link provider that adds this links is here. To execute the example, this is the command:

Windows
    %java -classpath 
            "libjavassist.jar;buildreflex-core.jar;buildreflex-examples.jar"
            reflex.examples.tutorial.ArgumentCheckingAspect

Linux
    %java -classpath
            "lib/javassist.jar:build/reflex-core.jar:build/reflex-examples.jar"
            reflex.examples.tutorial.ArgumentCheckingAspect

The output should be the same as in executing the Fibonacci class, because the default fibonacci numbers calculated are 5 and 6:

The fibonacci[5] is 5

The fibonacci[6] is 8

If you want to test the argument checking, put a second negative paramenter, for example:

Windows
    %java -classpath 
            "lib\javassist.jar;build\reflex-core.jar;build\reflex-examples.jar"
            reflex.examples.tutorial.ArgumentCheckingAspect -1

Linux
    %java -classpath
            "lib/javassist.jar:build/reflex-core.jar:build/reflex-examples.jar"
            reflex.examples.tutorial.ArgumentCheckingAspect -1

You should see something like:

Exception in thread "main" java.lang.IllegalArgumentException:
The argument must be a non-negative integer:-1
at reflex.examples.tutorial.ArgumentCheckingAspect$PositiveNumberChecker
    .check(ArgumentCheckingAspect.java:62)
at reflex.examples.fibonacci.app.Fibonacci.get(Fibonacci.java)
at reflex.examples.fibonacci.app.Fibonacci.main(Fibonacci.java:18)

In the following section we will see how to implement this using Reflex restrictions.

Using Restrictions

In Reflex, the execution of an aspect is subject to two conditions: its activation condition and a set of restrictions. The difference between them is that the activation condition can be changed at runtime, whereas restrictions can not.

Restrictions are public static methods defined in any class that returns a boolean value indicating whether a metaobject should be executed or not.

In our example we will define a metaobject that only throws the IllegalArgumentException: the argument checking will be done at the restriction method.

The hookset code remains the same:

Hookset theHookset = new PrimitiveHookset(
        MsgReceive.class,
        new NameCS("reflex.examples.fibonacci.app.Fibonacci"),
        new NameOS("get")
);

And the metaobject definition changes as we are using another metaobject:

MODefinition theMO = new MODefinition.SharedMO(new ExceptionThrower());

Here we use the ExceptionThrower class, that is defined this way:

public static class ExceptionThrower{
 
    public void throwException(int anArgument){
        throw new IllegalArgumentException("The argument must be " + 
        "non-negative:" + anArgument);
    }
 
    public static boolean check(int anArgument){
        return anArgument < 0;
    }
}

Notice that we have defined both the method that throws the IllegalArgumentException and the restriction method. This is only for convenience: the restriction can be defined anywhere. Finally, the code of the definition and configutarion of the link is:

BLink theLink = Links.get(theHookset, theMO);
theLink.setControl(Control.BEFORE);
theLink.setCall(Control.BEFORE, 
                 ExceptionThrower.class.getName(),
                 "throwException",
                 new StdParameters.IndexedArgument(0));
theLink.addRestriction(new Restriction(ExceptionThrower.class.getName(),"check",
                       new StdParameters.IndexedArgument(0)));

In the code above we can see almost the same configuration we used in the previous example. The only difference is that now, we have added a restriction that will be checked to determine if the metaobject should be executed. As you can see, the restrictions are defined making use of call descriptors, allowing us to specify the exact method we want to call.

The complete code of the link provider that adds this link to the configuration is here. And to execute this example, the command to execute is:

Windows
    %java -classpath
            "lib\javassist.jar;build\reflex-core.jar;build\reflex-examples.jar"
            reflex.examples.tutorial.RestrictionArgumentCheckingAspect

Linux
    %java -classpath
            "lib/javassist.jar:build/reflex-core.jar:build/reflex-examples.jar"
            reflex.examples.tutorial.RestrictionArgumentCheckingAspect

The output should be the same as in executing the Fibonacci class, because the default Fibonacci numbers calculated are 5 and 6:

The fibonacci[5] is 5

The fibonacci[6] is 8

If you want to test the argument checking, put a second negative paramenter, for example:

Windows
    %java -classpath
            "lib\javassist.jar;build\reflex-core.jar;build\reflex-examples.jar"
            reflex.examples.tutorial.RestrictionArgumentCheckingAspect -1

Linux
    %java -classpath
            "lib/javassist.jar:build/reflex-core.jar:build/reflex-examples.jar"
            reflex.examples.tutorial.RestrictionArgumentCheckingAspect -1

You should see something like this:

Exception in thread "main" java.lang.IllegalArgumentException:
The argument must be a non-negative integer:-1
at reflex.examples.tutorial.RestrictionArgumentCheckingAspect$ExceptionThrower
    .throwException(RestrictionArgumentCheckingAspect.java:69)
at reflex.examples.fibonacci.app.Fibonacci.get(Fibonacci.java)
at reflex.examples.fibonacci.app.Fibonacci.main(Fibonacci.java:18)