Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

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.

Monday, December 27, 2010

Bookmark and Share

One of the new features introduced with version 3.0 of the Spring framework is the Spring Expression Language or short "SpEL". This language is tailored for the needs when working with Spring and can be used when creating XML/annotation based Spring bean definitions for instance.

So I thought it would be nice if it was possible to use SpEL together with Hibernate Validator's @ScriptAssert constraint which allows to express validation routines using script or expression languages.

Unfortunately this does not work since currently no SpEL language binding for JSR 223 ("Scripting for the JavaTM Platform") exists. As @ScriptAssert's validator uses JSR 223 for expression evaluation at least for now SpEL can't be used along with @ScriptAssert (there is an issue in Spring's JIRA addressing this problem).

But as shown in previous posts it is very simple to create new constraint annotations for the Bean Validation API. So the idea is to build a new constraint @SpelAssert which resembles HV's @ScriptAssert but works with SpEL instead of the JSR 223 API.

Defining the annotation type is straight-forward:

1
2
3
4
5
6

7
8
9
10
11
12
13
14
15

@Target({ TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = SpelAssertValidator.class)
@Documented
public @interface SpelAssert {


    String message() default "{de.gmorling.moapa.bvspel.SpelAssert.message}";

    Class<?>[] groups() default {};


    Class<? extends Payload>[] payload() default {};

    String value();


}

Besides the standard attributes message(), groups() and payload() mandated by the BV specification we define one more attribute value(), which takes the SpEL expression to evaluate.

Now let's come to the validator:

1
2
3
4
5
6

7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
public class SpelAssertValidator implements

ConstraintValidator<SpelAssert, Object> {

    @Inject
    private ExpressionParser parser;

    private Expression expression;


    @Override
    public void initialize(SpelAssert constraintAnnotation) {

    String rawExpression = constraintAnnotation.value();


        if (rawExpression == null) {
            throw new IllegalArgumentException("The expression specified in @"

                + SpelAssert.class.getSimpleName() + " must not be null.");
        }

        expression = parser.parseExpression(rawExpression);
    }


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

        if (value == null) {

            return true;
        }

        return Boolean.TRUE.equals(expression.getValue(value, Boolean.class));

    }
}

In initialize() we use an ExpressionParser to parse the specified SpEL expression (so this happens only once) and evaluate the given object against it in isValid().

But wait a minute, where does the ExpressionParser come from, it is not instantiated here?

Right, the cool thing is Spring comes with it's own ConstraintValidatorFactory which performs dependency injection on constraint validators. A validator relying on that feature of course is not portable, but as this validator is based on SpEL and Spring anyways this is not an issue here.

In order to have this working a parser bean must be part of the Spring application context. We just register a SpelExpressionParser:

1

2
3
4
5
6
7
8
9
10

11
12
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="parser"
        class="org.springframework.expression.spel.standard.SpelExpressionParser"/>


    <bean id="validator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</beans>

This context also shows how to provide a BV Validator for dependency injection leveraging Spring's LocalValidatorFactoryBean.

Now let's have a look at the @SpelAssert constraint in action. The following shows the canonical example of a class CalendarEvent where the start date shall always be earlier than the end date:

1

2
3
4
5
6
7
8
9
10

@SpelAssert("startDate < endDate")
public class CalendarEvent {


    private Date startDate;

    private Date endDate;


    // getters, setters etc.

}

Note how SpEL allows dates to be compared using the "<" operator and that no alias for the evaluated bean is required, as all unqualified attribute/method names are resolved against the annotated object.

Finally we should have a test showing that the validator works as expected by validating a valid and an invalid CalendarEvent instance:

1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration
public class SpelAssertTest {

    @Inject
    private Validator validator;


    private Date startDate;
    private Date endDate;

    @Before

    public void setUpDates() {

        Calendar start = Calendar.getInstance();
        start.set(2010, 13, 24);

        startDate = start.getTime();

        Calendar end = Calendar.getInstance();
        end.set(2010, 13, 26);

        endDate = end.getTime();
    }

    @Test
    public void validEvent() {


        CalendarEvent event = new CalendarEvent();
        event.setStartDate(startDate);
        event.setEndDate(endDate);

        assertTrue(validator.validate(event).isEmpty());

    }

    @Test
    public void invalidEventYieldsConstraintViolation() {

        CalendarEvent event = new CalendarEvent();

        event.setStartDate(endDate);
        event.setEndDate(startDate);

        Set<ConstraintViolation<CalendarEvent>> violations = 
            validator.validate(event);

        assertEquals(1, violations.size());

        ConstraintViolation<CalendarEvent> violation = 
            violations.iterator().next();
        assertEquals(

            "SpEL expression \"startDate < endDate\" didn't evaluate to true.",
            violation.getMessage());
    }

}

The complete sources for this post can be found at GitHub, so don't hesistate to give it a try or use it in your projects if you like. Any feedback or ideas for improvement are warmly welcome.

Monday, March 23, 2009

Bookmark and Share

JAX-WS is the standard API of the Java platform not only for the creation of web service providers but also for building web service clients. In the following I will show how to build and test a web service client using the JAX-WS reference implementation (RI) in conjunction with the Spring framework.

The example: A client for a simple shop web service

As example a simple client for an exemplary shop web service shall be built, that allows to search for products by their id. The WSDL looks as follows (this is a slightly simplified version of the WSDL from the shop service example which is part of the maven-instant-ws project):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="UTF-8"?>
<definitions 
    name="Products" 
    targetNamespace="http://www.gmorling.de/jaxwsonspring/products"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://www.gmorling.de/jaxwsonspring/products"
    xmlns:products="http://www.gmorling.de/jaxwsonspring/products/types"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">

    <types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import namespace="http://www.gmorling.de/jaxwsonspring/products/types"
                schemaLocation="products.xsd" />
        </xsd:schema>
    </types>

    <message name="GetProductByIdRequestMessage">
        <part name="body" element="products:GetProductByIdRequest" />
    </message>
    <message name="GetProductByIdResponseMessage">
        <part name="body" element="products:GetProductByIdResponse" />
    </message>

    <portType name="ProductsPortType">
        <operation name="GetProductById">
            <input message="tns:GetProductByIdRequestMessage" />
            <output message="tns:GetProductByIdResponseMessage" />
        </operation>
    </portType>

    <binding name="ProductsSoapBinding" type="tns:ProductsPortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <operation name="GetProductById">
            <soap:operation soapAction="GetProductById" />
            <input>
                <soap:body use="literal" />
            </input>
            <output>
                <soap:body use="literal" />
            </output>
        </operation>
    </binding>

    <service name="ProductsService">
        <port name="ProductsPort" binding="tns:ProductsSoapBinding">
            <soap:address location="TODO" />
        </port>
    </service>
</definitions>

The WSDL basically defines a single operation, GetProductById, that takes a GetProductByIdRequest object and returns a GetProductByIdResponse object. These types are specified in a separate XML schema:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.gmorling.de/jaxwsonspring/products/types"
    xmlns="http://www.w3.org/2001/XMLSchema" xmlns:products="http://www.gmorling.de/jaxwsonspring/products/types">

    <!-- GetProductById -->
    <element name="GetProductByIdRequest">
        <complexType>
            <sequence>
                <element name="Id" type="int" />
            </sequence>
        </complexType>
    </element>
    <element name="GetProductByIdResponse">
        <complexType>
            <sequence>
                <element type="products:Product" name="Product" minOccurs="0" />
            </sequence>
        </complexType>
    </element>

    <!-- General-purpose types -->
    <complexType name="Product">
        <sequence>
            <element name="Id" type="int" />
            <element name="Name" type="string" />
            <element name="Price" type="decimal" />
            <element name="Size" type="string" minOccurs="0" />
        </sequence>
    </complexType>
</schema>

The request type is just a wrapper for an int parameter representing a product id, while the response type contains a Product element, which itself has a name, price etc.

Generating proxy classes

JAX-WS provides a tool called wsimport which takes the WSDL of a web service and generates proxy classes for the WSDL's service and port definitions. These can then be used to access the web service endpoint.

With the help of the JAX-WS Maven plugin the wsimport tool can easily be used in Maven based projects. Just configure the wsimport goal of the plugin in your project's pom.xml as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
<build>
    ...
    <plugins>
        ...
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
            </configuration>
        </plugin>
        ...     
    </plugins>
    ...
</build>
...

The WSDL to be processed can either be fetched directly from the actual web service endpoint or from a local directory (by specifying the wsdlDirectory property as shown in the example). I recommend to stick with the latter approach. That way your project can be built even if the service to be accessed is not available from your development environment.

During the "generate-sources" build lifecycle phase the plugin will generate

  • proxy classes for all service and port type declarations contained within the WSDL files in the specified directory
  • JAXB binding classes for all schema types used in the operations of that services

Using the proxy classes generated from the shop service WSDL it is not too hard to build a simple shop client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package de.gmorling.jaxwsonspring;

import javax.xml.ws.BindingProvider;

import de.gmorling.jaxwsonspring.shop.products.ProductsPortType;
import de.gmorling.jaxwsonspring.shop.products.ProductsService;
import de.gmorling.jaxwsonspring.shop.products.types.GetProductByIdRequest;

public class ShopClient {

    private final static String END_POINT_URL = "http://localhost:8080/shopserver/Products";

    public String getProductNameByid(int productId) {

        GetProductByIdRequest request = new GetProductByIdRequest();
        request.setId(productId);

        ProductsService productsService = new ProductsService();
        ProductsPortType productsPort = productsService.getProductsPort();
        ((BindingProvider) productsPort).getRequestContext().put(
            BindingProvider.ENDPOINT_ADDRESS_PROPERTY, END_POINT_URL);

        return productsPort.getProductById(request).getProduct().getName();
    }
}

All you have to to do is to instantiate the ProductsService, retrieve the ProductsPort from it, set the endpoint address and call any of the port's operations.

Portability issues

This works basically pretty well, but I ran into a problem, as I tried to execute my project's binary on a different machine – suddenly the WSDL of the service couldn't be found. Searching the web a little bit I found out, that JAX-WS RI parses the WSDL each time a Service instance is created.

The WSDL's location is taken from an annotation of the generated Service class (ProductsService in this case), where it is unfortunately specified as an absolute path. That causes the Service initialization to fail if the project is moved to another directory or to another system, where the WSDL doesn't exist at the expected location.

This problem can be solved by specifying the WSDL location relatively when instantiating the Service class. This complicates the process of obtaining web service port references a little bit, therefore I thought it might be a good idea to make use of dependency injection (DI). That way the rather ugly API for setting the endpoint address can be hidden from the caller as well and DI finally allows to inject mock port implementations in unit tests.

Spring's JaxWsPortProxyFactoryBean

At first I considered building a custom solution using the Spring DI container, but then I stumbled upon Spring's JaxWsPortProxyFactoryBean that already provides DI services for JAX-WS client ports.

Using that bean a JAX-WS port can be configured within a Spring application context as follows:

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

    <bean id="productsPort" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
        <property name="serviceInterface" value="de.gmorling.jaxwsonspring.shop.products.ProductsPortType" />
        <property name="wsdlDocumentUrl" value="wsdl/products.wsdl" />
        <property name="namespaceUri" value="http://www.gmorling.de/jaxwsonspring/shop/products" />
        <property name="serviceName" value="ProductsService" />
        <property name="endpointAddress" value="http://localhost:8080/jaxws-on-spring-server/Products" />
    </bean>
</beans>

So basically you have to configure the type of the port to be injected (the attribute name "serviceInterface" seams a bit irritating to me), the URL of the WSDL (e.g. identifying a classpath resource), namespaceUri and serviceName as specified in the WSDL file and finally the address of the endpoint to be used.

A word on thread safety

When configured as shown above Spring will use the singleton scope for the productsPort bean. That means the bean will exist only once and potentially be accessed from multiple threads at the same time.

Unfortunately the JAX-WS specification doesn't clearly say whether the generated service and port classes are thread-safe or not. Therefore one generally should assume that they aren't.

But after some searching, I found a comment by one of the JAX-WS RI developers stating, that the proxy classes of JAX-WS RI are thread-safe, as long as the request context of a port instance isn't modified. Assuming that no user of the bean modifies its request context (e.g. by re-setting the endpoint address) we are fine with the singleton scope for now.

Injecting JAX-WS client ports

Now let's rewrite the ShopClient class by having the productsPort bean injected into it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package de.gmorling.jaxwsonspring;

import javax.annotation.Resource;

import de.gmorling.jaxwsonspring.shop.products.ProductsPortType;
import de.gmorling.jaxwsonspring.shop.products.types.GetProductByIdRequest;

public class ShopClient {

    @Resource
    private ProductsPortType productsPort;

    public String getProductNameByid(int productId) {

        GetProductByIdRequest request = new GetProductByIdRequest();
        request.setId(productId);

        return productsPort.getProductById(request).getProduct().getName();
    }

}

Of course we need to configure ShopClient as Spring bean as well:

1
2
3
...
<bean id="shopClient" class="de.gmorling.jaxwsonspring.ShopClient" />
...

When creating the shopClient bean Spring will process the @Resource annotation (which stems from JSR 250: "Common Annotations for the JavaTM Platform") by populating the productsPort field with the bean of the same name.

Mocking web service requests in unit tests

Leveraging dependency the ShopClient class is greatly simplified now. As last step let's create a unit test for it.

To do so we should work with a mock implementation of the ProductsPortType interface. Working with a mock instead of accessing the real shop web service does not only increase the performance of the unit test. It also ensures, that the test result isn't dependent on the service's availability or its proper functioning.

For creating the mock we will use the freely available Mockito framework in the following (alternatively we could work with EasyMock or JMockit).

In the Spring application context for the unit test we specify that the productsPort bean shall be created by calling the method org.mockito.Mockito#mock(), which expects the class object of the object to be mocked as parameter:

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

    <bean id="productsPort" class="org.mockito.Mockito" factory-method="mock" >
        <constructor-arg index="0" value="de.gmorling.jaxwsonspring.shop.products.ProductsPortType" />
    </bean>

    <bean id="shopClient" class="de.gmorling.jaxwsonspring.ShopClient" />
</beans>

Next we have to define, how the mock shall behave, when it is called by the code under test. For doing so we inject the productsPort bean into our test class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package de.gmorling.jaxwsonspring;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.math.BigDecimal;

import javax.annotation.Resource;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import de.gmorling.jaxwsonspring.shop.products.ProductsPortType;
import de.gmorling.jaxwsonspring.shop.products.types.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ShopClientTest {

    @Resource
    private ProductsPortType productsPort;

    @Resource
    private ShopClient shopClient;

    @Before
    public void instructMock() {
        GetProductByIdResponse response = new GetProductByIdResponse();
        Product product = new Product();
        product.setId(1);
        product.setName("Jeans-Hose");
        product.setPrice(new BigDecimal("89.99"));
        product.setSize("L");
        response.setProduct(product);

        when(productsPort.getProductById(
            any(GetProductByIdRequest.class))).thenReturn(response);
    }

    @Test
    public void getProductName() {
        assertEquals("Jeans-Hose", shopClient.getProductNameByid(1));
    }

}

In the instructMock() method we first create a sample response object. Then we specify, that whenever the getProductById() of the mock is called, this response object shall be returned.

As the productsPort bean has singleton scope, the same instance of the bean will be injected into the shopClient bean. That way the shopClient bean will finally return the expected product name within the actual test method.

Conclusion

JAX-WS is a powerful API not only for the creation of web service providers but also for building web service clients. Unfortunately the devil is in the details – when not handled properly, JAX-WS will try to read WSDL files using absolute file pathes and setting end point addresses is not very intuitive as well.

Luckily the Spring framework comes to the rescue by enabling the creation of web service ports using dependency injection. That way obtaining port references is not only greatly simplified, it also allows mocking actual web service requests within unit tests.

The complete source code from this post can be downloaded here. As always I'd be happy about any comments and ideas for improvement.

Sunday, February 22, 2009

Bookmark and Share

JSR 303 ("Bean Validation") specifies a fairly simple to use bootstrapping API for the creation of Validator instances:

1
2
3
4
...
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
...

To make things even easier, one can use a dependency injection container such as the Spring container to obtain Validator instances. That way you don't have to cope with the ValidatorFactory in your application logic but rather can have Validator instances simply injected. All you have to do for that is to create a Spring application context, that defines two Spring beans validatorFactory and validator as follows:

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

    <bean id="validatorFactory" class="javax.validation.Validation"
        factory-method="buildDefaultValidatorFactory" />

    <bean id="validator" factory-bean="validatorFactory"
        factory-method="getValidator" />
</beans>

The validationFactory bean is created by instructing Spring to call the static factory method Validation.buildDefaultValidatorFactory(). The validator bean in turn is created by letting Spring call the getValidator() method on the validatorFactory bean.

As we don't specify any scope for the two beans explicitely, the default scope Singleton will be used. That way the Spring container will instantiate both beans exactly once and return these instances whenever requested. We are fine with that, as the Bean Validation specification states, that ValidatorFactory and Validator implementations have to be thread-safe.

The validator bean can now be injected into any other bean we create. Using Spring's test framework we can have the comfort of dependency injection also in JUnit tests. Let's try it out by using an injected Validator to validate instances of the exemplary Car class from my introductory post on the Bean Validation API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package de.gmorling.bvspring;

import static org.junit.Assert.*;

import java.util.Set;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class CarTest {

    @Resource
    private Validator validator;

    @Test
    public void licensePlateTooShort() {

        Car car = new Car("Morris", "D", 4);

        Set<ConstraintViolation<Car>> constraintViolations = validator
                .validate(car);

        assertEquals(1, constraintViolations.size());
        assertEquals("size must be between 2 and 14", constraintViolations
                .iterator().next().getInterpolatedMessage());
    }

    @Test
    public void carIsValid() {

        Car car = new Car("DD-AB-123");

        Set<ConstraintViolation<Car>> constraintViolations = validator
                .validate(car);

        assertEquals(0, constraintViolations.size());
    }

}

With JUnit's @RunWith annotation we declare that the test runner SpringJUnit4ClassRunner shall be used to run the test, which enables Spring to inject dependencies into the test class.

The @ContextConfiguration stems from Spring's test framework and specifies the application context to be used. As we don't provide any name, Spring will use the default name, which is de/gmorling/bvspring/CarTest-context.xml in our case.

The @Resource annotation finally is defined by JSR 250 ("Common Annotations for the JavaTM Platform") and is used here to signal, that the validator field shall be populated by Spring. Spring processes the @Resource annotation following by-name semantics, meaning that a Spring bean with the name "validator" will be searched in the application context and injected into the field.

One final word on a version incompatibility between Spring and JUnit I noticed. Using JUnit 4.5 gave me the following error:

1
java.lang.NoSuchMethodError: org.junit.runner.notification.RunNotifier.testAborted(Lorg/junit/runner/Description;Ljava/lang/Throwable;)

So be sure to use JUnit 4.4. A complete Maven project with this post's source files can be downloaded here.