Sunday, June 10, 2012

Bookmark and Share

The Spring framework has in general an excellent documentation. One exception to me is the reference guide's chapter on Spring AOP, which I personally find not as comprehensible as other parts of the documentation.

What I'm missing in particular is a complete example demonstrating how to use Spring AOP together with AOP Alliance MethodInterceptors. Where possible, I prefer to use AOP Alliance compliant interceptors over other Spring AOP advice types, as they foster interoperability with other AOP frameworks compatible with the AOP Alliance API, such as Google Guice.

So without further ado, an example for using AOP Alliance method interceptors with Spring AOP is shown in the following.

First define an interceptor by implementing the interface org.aopalliance.intercept.MethodInterceptor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component
public class InvocationCountInterceptor implements MethodInterceptor {

    private AtomicLong invocationCount = new AtomicLong();

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        invocationCount.incrementAndGet();
        return invocation.proceed();
    }

    public AtomicLong getInvocationCount() {
        return invocationCount;
    }
}

By specifying the @Component stereotype annotation, the interceptor is enabled to be detected automatically by the Spring container using component scanning.

Now the types/methods to which the interceptor shall be applied need to be configured. Using Spring's AOP schema, this is done by defining an advisor which references the interceptor bean and links it with a pointcut expression describing the targeted methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd      
    ">

    ...
    <aop:config>
        <aop:advisor advice-ref="invocationCountInterceptor" pointcut="within(de.gmorling.moapa.springaop.service..*)"/>
    </aop:config>
    ...

</beans>

Here the interceptor is applied to all invocations of methods defined within the de.gmorling.moapa.springaop.service package and its sub-packages. But the pointcut could also be more fine-grained and match only methods on specific types or even single methods.

If several interceptors shall be bound to the same pointcut, the pointcut expression can also be defined separately and referenced from multiple advisors like so:

1
2
3
4
5
6
7
...
<aop:config>
    <aop:pointcut id="serviceLayer" expression="within(de.gmorling.moapa.springaop.service..*)"/>
    <aop:advisor advice-ref="invocationCountInterceptor" pointcut-ref="serviceLayer"/>
    <aop:advisor advice-ref="anotherInterceptor" pointcut-ref="serviceLayer"/>
</aop:config>
... 

Note that the AspectJ weaver JAR and – when applying interceptors to classes – CGLIB 2 need to be on the class path. A complete sample Maven project can be found on GitHub.

Sunday, October 9, 2011

Bookmark and Share

While working on a little pet project based on OSGi I wanted to use the Pax Runner Eclipse plug-in to launch my OSGi application on the Apache Felix OSGi framework.

Unfortunately this attempt resulted in the following error:

1
2
3
4
5
6
7
8
9
10
java.lang.NoClassDefFoundError: org/eclipse/pde/internal/ui/launcher/LaunchArgumentsHelper
at org.ops4j.pax.cursor.Utils.getVMArgsOptions(Utils.java:216)
at org.ops4j.pax.cursor.LaunchConfiguration.getProgramArguments(LaunchConfiguration.java:156)
at org.eclipse.pde.launching.AbstractPDELaunchConfiguration.launch(AbstractPDELaunchConfiguration.java:72)
at org.eclipse.pde.launching.OSGiLaunchConfigurationDelegate.launch(OSGiLaunchConfigurationDelegate.java:47)
at org.eclipse.debug.internal.core.LaunchConfiguration.launch(LaunchConfiguration.java:853)
at org.eclipse.debug.internal.core.LaunchConfiguration.launch(LaunchConfiguration.java:702)
at org.eclipse.debug.internal.ui.DebugUIPlugin.buildAndLaunch(DebugUIPlugin.java:923)
at org.eclipse.debug.internal.ui.DebugUIPlugin$8.run(DebugUIPlugin.java:1126)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

This looked pretty much like an incompatability between the Pax Runner plug-in and the Eclipse platform. And indeed the plug-in unfortunately doesn't seem to keep up with PDE-internal changes in recent Eclipse versions due to limited developer resources.

Further googling then led me to PAXRUNNER-353 at Pax Runner's issue tracker.

The ticket itself is not yet resolved, but the good news is that Christian Baranowski (whom I had the pleasure to meet during the OSGi code camp last week) created a fork on GitHub fixing the issue for now. So let's hope that this fix gets quickly merged into the main branch.

Until then Christian even has established a temporary Eclipse update site which makes upgrading the plug-in to the forked version a breeze.

So my kudos go to Christian (for fixing the plug-in) and to GitHub (for making forking easy) :-)

Monday, August 1, 2011

Bookmark and Share

Maybe you know it already: last week JSR 349 successfully passed the review ballot, meaning that the work on a new release of the Bean Validation API has officially started.

I'm really excited about this, because I've got the pleasure to be part of the JSR 349 expert group. I haven't been member of such a comitee before, so I guess this will be exciting times and I'll surely learn a whole lot of new things during the work on the specification.

What's most important right now is your feedback: what new features would you like to see included in Bean Validation 1.1, what problems did you face when working with BV 1.0 which you think should be addressed in the next release?

Your input and feedback is highly welcome at several places:

  • The Bean Validation feedback forum is a good platform for discussing ideas, requests for clarifications etc.
  • For concrete feature requests or bug reports you can open an issue at the Bean Validation issue tracker

As a starting point you might want to check out these two blog posts by Emmanuel Bernard (the Bean Validation spec. lead), where a lot of possible features are discussed.

Finally I'd like to point your attention to http://beanvalidation.org/, the JSR's official web site. There you'll find everything related, e.g. a news section, the road map and also the Bean Validation 1.0 spec. document for reference.

Now it's up to you – tell us what would YOU like to see included in Bean Validation 1.1.

Sunday, May 8, 2011

Bookmark and Share

Note: This article originally appeared on in.relation.to as part of the Seam Module Spotlight series. In order to spread the word on Seam Validation I thought it might be a good idea to post it in this blog, too.

Seam Validation is a relatively new Seam module which provides an integration between Hibernate Validator which is the reference implementation of the Bean Validation standard (JSR 303) and CDI. The module's functionality falls into two areas:

  • Enhanced dependency injection services for validators, validator factories and constraint validators
  • Automatic validation of method parameters and return values based on Hibernate Validator's method validation API

Let's take a closer look at these features in the following.

Dependency injection services

The Bean Validation API is an integral part of the Java EE platform. So when running on a Java EE 6 compatible application server such as JBoss AS 6 you can easily retrieve Validator and ValidatorFactory instances via dependency injection.

Unfortunately this is not working out of the box when running in non-EE environments such as plain servlet containers. But don't worry, Seam Validation comes to the rescue. By adding the module as dependency to your project, validators and validator factories can be obtained using @Inject:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Foo {

    @Inject
    private Validator validator;

    public void doSomething() {

        Bar bar = new Bar();

        Set<ConstraintViolation<Bar>> constraintViolations = validator.validate(bar);
        //examine the violations ...
    }
}

But Seam Validation goes one step further and enables dependency injection also within constraint validator implementations. For instance we might have a custom constraint @ValidLicensePlate which is used to ensure that a car has a license plate which is properly registered, still valid etc.:

1
2
3
4
5
6
7
public class Car {

    @ValidLicensePlate
    private String licensePlate;

    //constructor, getter, setter etc.
}

In order to perform the required checks the constraint's validator invokes some sort of registration service (note: accessing external services can potentially be an expensive operation, so it may be a good idea to put the constraint into a separate validation group, but that's out of scope for this article). The Seam Validation module allows to inject this service into the validator as into any other CDI bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ValidLicensePlateValidator implements ConstraintValidator<ValidLicensePlate, String> {

    @Inject
    private RegistrationService registrationService;

    @Override
    public void initialize(ValidLicensePlate constraintAnnotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {

        if (value == null) {
            return true;
        }

        //delegate to registration service
        return registrationService.isValid(value);
    }
}

There is just on more step required before the @ValidLicensePlate constraint can be used: We have to register Seam Validation's constraint validator factory with the Bean Validation provider. This happens by putting a file named validation.xml with the following content into the META-INF folder of the application:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<validation-config 
    xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd">

    <constraint-validator-factory>
        org.jboss.seam.validation.InjectingConstraintValidatorFactory
    </constraint-validator-factory>
</validation-config>

Method validation

The other main feature of Seam Validation besides dependency injection is the automatic validation of method parameters and return values based on the API for method validation introduced with Hibernate Validator 4.2 (note: at the time of writing Hibernate Validator 4.2 is released as Beta version, but no major changes are expected until the final release).

This API provides an easy-to-use facility for the "Programming by Contract" approach to program design based on the concepts defined by the Bean Validation API. That means that any Bean Validation constraint can be used to describe

  • the preconditions that must be met before a method may be invoked (by annotating method parameters with constraints) and
  • the postconditions that are guaranteed after a method invocation returns (by annotating methods).

Things should become clearer with an example:

1
2
3
4
5
6
7
8
9
@AutoValidating
public class RentalStation {

    @Valid
    public Car rentCar(@NotNull CustomerPK customerPK, @NotNull @Future Date startDate, @Min(1) int durationInDays) {

        //highly complex car rental business logic ...
    }
}

Here the following pre- and postconditions are applied onto the rentCar() method:

  • The customer's primary key may not be null
  • The rental start date must not be null and must be in the future
  • The rental duration must be at least one day
  • The returned object must be valid with respect to all constraints of the Car class

By annotating the class RentalStation with @AutoValidating, all these constraints are automatically validated by a method interceptor whenever the rentCar() method is invoked. If any of the constraints can't be validated successfully, a runtime exception describing the occurred constraint violation(s) is thrown.

This approach has several advantages over traditional parameter and return value checking:

  • The checks don't have to be performed by hand. This results in less boiler-plate code to write (and to read).
  • A method's pre- and postconditions are part of its API and generated documentation. It's not necessary to add comments such as "returns never null", as this information will automatically be put into the generated JavaDoc. This results in less redundancies and hence in less potential inconsistencies between implementation and documentation.

Future steps

This concludes our short tour through the Seam Validation module. If you feel like trying out the module yourself, the module home page is the right starting point. You might also be interested in the module's reference guide, and in case you found a bug or want to create a feature request the module's JIRA instance is the place to go.

Possible future developments of Seam Validation include a closer integration with other Seam 3 modules, the possibility to chose the validation groups to be used for method validation and the evaluation of standard bean constraints upon method validation.

Saturday, March 5, 2011

Bookmark and Share

I need your help.

To be more concise, I need your vote for the 2011 JBoss Community Recognition Awards.

These awards are an effort of JBoss/Red Hat to honor significant contributions to the JBoss community over the last year and I'm more than proud to say that I've been nominated in the "New Features" category for my contributions to Hibernate Validator.

So if you appreciate my work on Hibernate Validator – e.g. the HV annotation processor or the method validation feature I've built for HV 4.2 – or the Validation module for Seam 3 (I'll blog on this in a separate post) I've recently started, just head over to the poll and give me your vote. The voting is open until April, 2nd.

And if you really like my work, go and tell your friends that they should vote for me, too.

Just in case you feel like you need some more information to make a profound vote you might also check out my nominee description.

Another nomination I'd like to mention is the one of my fellow developer Kevin Pollet in the "Bug Fixes" category. He has done some really awesome work for HV 4.2. Besides fixing many bugs he implemented several new features like the integration with the Joda time API or the support for dynamic default group sequence definitions.

So when you (and your friends) have voted for me, don't forget to vote for Kevin, too :)