Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] args() and @args() for indeterminite lists of parameters?

I'm continuing to play around with some design-by-contract ideas.

I've been implementing an abstract that catches null parameters and
throws IllegalArgumentException.

Been learning a lot, here's what I've got so far:

@SuppressNullCheck
public abstract aspect AbstractCatchNullParametersAspect
{
    /**
     * Overridden in concrete aspects to identify which classes are
affected (typically, all within
     * a particular package).
     */
    abstract pointcut targetClasses();

    pointcut typeNotMarkedAsSuppressed() :
        !within(@SuppressNullCheck Object+);

    /** Look for methods and constructors that do NOT have the
SuppressNullCheck annotation. */
    pointcut codeNotMarkedAsSuppressed() :
        execution(!@SuppressNullCheck !private * *(..)) ||
        execution(!@SuppressNullCheck !private new(..));

    /**
     * Exclude methods (and constructors) with no parameters. Also,
exclude equals() since it has to
     * accept null (and we don't want to force you to put the
SupportNullCheck annotation on every
     * class that overrides equals().
     */
    pointcut excludedMethods() :
        execution(* *()) ||
        execution(new ()) ||
        execution(boolean equals(Object));

    /**
     * Because this aspect can apply so widely, we explicitly exclude
the aspect from advising
     * itself.
     */
    pointcut methodsToCheck()  :
        targetClasses() &&
        typeNotMarkedAsSuppressed() &&
        codeNotMarkedAsSuppressed() &&
        !excludedMethods();

    pointcut parametersToCheck(Object argumentValue) :
        args(.., argumentValue);

    /**
     * Here's where the real work gets done. I think there may be a
way to do this more efficiently
     * where much more static logic is injected, triggered by arguments.
     */
    before(Object argumentValue) : methodsToCheck() &&
parametersToCheck(argumentValue)
    {
        if (argumentValue == null)
        {
            // The method signature could provide the parameterName
(which would be awesome),
            // but we need to know the parameter index.

            String message = String.format(
                    "Parameter passed to method %s (at %s) was null.",
                    thisJoinPoint.getSignature().toString(),
                    thisJoinPoint.getSourceLocation());

            throw new IllegalArgumentException(message);

        }
    }
}

It works quite well (though I haven't tried to, for example, check the
performance hit).

A couple of things I'd like:

1) According to AJDT, methods that take primitive parameters are still
being advised.

2) I'd love it if there was some way to determine the parameter index,
because then my exception message could include the parameter name
(i.e., by casting to MethodSignature)

3) I'd like to be able to skip the check for arguments what are
annotated with an @AllowNull annotation,  but I haven't quite seen how
I can coordinate the check (given that I'm doing these arbitrary
method matches).

And ideas?  It's been fun.

--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com


Back to the top