Monday, May 13, 2013

Retrieving method annotations with Spring Annotation Utils

1   Introduction

The JDK provides us with several lookup methods that allow us to retrieve annotations from a class, method, field or added to method parameters. The Spring framework included a general utility class for annotations, org.springframework.core.annotation.AnnotationUtils, which extends the basic functionalities. In this post I will explain the main features of this class, focusing on retrieving annotations from a method.


2   getAnnotation method

Signature:
This method looks up if method contains the specified annotation type and returns it if found. So, what's the difference between the JDK getAnnotation method? The Spring version handles bridge methods. You can check effects of Type Erasure and Bridge Methods tutorial to get a good explanation.

Let's see it with an example. Imagine we got a generic class Foo, and a Bar class that extends it:
Now we try to retrieve @MyAnnotation with both utility methods:
The result is as follows:



3   findAnnotation method

Signature:
This method also retrieves the specified annotation type from method. The difference between getAnnotation is that in this case, it will look up the entire inheritance hierarchy of the specified method.

Let's see another example. We got the classes below:
Trying to retrieve @MyAnnotation from anotherMethod in Bar class using the different utility methods
will get the following results:



Monday, April 29, 2013

Unit testing with PowerMock

In this article I will implement several unit tests using PowerMock framework. This framework is more powerful than other libraries and allows you to mock static methods, private methods and change field properties among other things. I will use the Mockito extension but it also supports EasyMock.


1   Installation


If you use Maven, you can add the following dependencies to your pom.xml:
Otherwise, you can get the libraries here.


2   Preparing the tests


You must add the @RunWith annotation. This annotation will tell JUnit to use the class PowerMockRunner to run the tests.
I'm going to test Foo.class. Using the spy method, all real methods of the class will be invoked except those I mock.


3   Mocking private methods


I want to test methodWithPrivateDependency, but this method internally calls a private method which, let's say, calls an external resource.
The test:
The @PrepareForTest annotation tells PowerMock to prepare the class so it can manipulate it. This is necessary if the class is final, or it contains final, private, static or native methods that should be mocked. In this case, I will need to mock the private method.

If you put this annotation at class level, it will affect all test methods within the class. It would be as follows:

4   Mocking static access


The next method that needs to be tested gets some information by accessing a static method of an inner static class. You need to mock the static access.

The method to test:
The static class:
The test:
I use the @PrepareForTest annotation because I need to mock the static method getData of this class.


5   Mocking chained dependencies


In this example, I want to mock the chainMocks method. There's a singleton Helper class which returns a manager from which the method to test invokes it.
The test:
I only need to prepare Helper class for test because I need to mock its static method getInstance (that's not the case for ConfigurationManager where initializeRegistry is a public instance method).

Wednesday, April 3, 2013

Communication in Spring Webflow 2

1   Introduction

This article tries to complement the reference documentation with examples on how to communicate within a flow in Spring Web flow 2, showing different ways to share data between controllers and views that form a flow. The article is divided into the following sections:
  • Setting flow variables
  • Setting attribute values
  • Using additional scopes
  • Communication with sub flows
  • Communication with other flows
  • Launching events with attributes
  • Accessing RequestContext
  • Accessing Spring beans
  • Using implicit variables

The example explained here uses Spring Web flow 2.3.1 and Spring 3.0.5 versions. You can get the source code here, with all the examples shown in this article.


2   Setting flow variables

There are different ways of setting variables and storing them into the flow scope, where they will then be accessible to controllers and views.

2.1   var element (variable)

The var element instantiates a class and stores it in the flow scope. Since the instance will be stored between flow requests, the class should implement java.io.Serializable. It does not allow you to assign a value, making this element useless for classes without a default constructor (it will crash at runtime with a nice NoSuchMethodException). In that case, you can use the set element (see section 3).

Defining a variable:

You can use this variable in the flow definition, for example, passing it as a parameter to a controller:

The method will receive the car parameter:
Since it is automatically stored in the flow scope, you can also retrieve the value from the request context:
Or use it in the view using for example ${car.color}

2.2   At flow starting point

If your class has no default constructor or you want to retrieve the instance from a service, the element var won't be enough. You can use a controller instead:
In this sample, the information could be retrieved from a service. The result attribute will get the object returned by the controller and store it in the flow scope.

You can also use this approach when entering a state (on-entry) or before rendering a view (on-render).

2.3   Anywhere in the flow

Since you have access to the Web flow RequestContext when invoking a controller, you can set a flow scoped variable as shown below:


3   Setting attribute values

The set element allows you to define an attribute and specify a scope. This element takes the following attributes:
  • name: Scope and name for the attribute, delimited by a dot (scope.name).
  • value: Value set to the attribute.
  • type: Class type.

For example, you can use it at the beginning of a flow (on-start) or when entering into a state (on-entry). The following sample show how to assign it a specified value when the flow starts:
Or you could set it when launching a transition:

The set element not only allows you to define objects, but also String values. For example, if you have a bean named 'myBean', the first set element in the following sample, will retrieve the Car instance from the bean and store it in the request scope with the name 'carObject'. On the other hand, the second set element will store in the request scope an attribute named 'carString' that will contain the String 'myBean.car'.

You can also use implicit variables when setting the value of the set element (see section 10 for a list of these variables):


4 Using additional scopes

The RequestContext interface contains access to all the other scopes defined in Spring Web flow: request, flash, view, flow and conversation.

You can also access these scopes at flow definition level by using implicit EL variables, which are: requestScope, flashScope, viewScope, flowScope and conversationScope.

For other scopes, you can use the external context:

At flow definition using implicit variables:

Or at controller level through RequestContext interface:


5   Communication with sub flows

When invoking a sub flow from the main flow, you can pass it input attributes. Once the sub flow has finished, it may return output attributes.

Input:
The input element allows you to send parameters to the sub flow. When the sub flow starts, these input attributes are stored in the flow scope of the sub flow. You will need to define the input element in the sub flow, using the same name attribute as used in the main flow.

Output:
Once the sub flow ends, the main flow can receive output parameters. These output parameters are defined within sub flow's end-states. When the execution returns to the main flow. output parameters will be available as attributes inside the launched event.

Main flow: invoking a sub flow

When returning to the main flow, you will need to define an attribute with the value returned by the sub flow in order to make it accessible to following states.

You could also invoke a controller that would set the value and store it in the needed scope:

Sub flow definition

There are other options to pass information to a subflow which consists in the following:
  • Storing the information at conversation scope (this scope is available from within a flow and its sub flows).
  • Pass the information in the transition which access the sub flow:


6   Communication with other flows

You have two options of passing data to another flow which is not related to the current flow:
  1. Session scoped attributes
  2. URL Request parameters
If you choose the second option, you can do it the following way:

In the view:

When starting the other flow, you can use the requestParameters implicit variable to retrieve the value and store it in the needed scope.

You could also do it in the controller:

Or use the requestParameterMap directly through the getRequestParameters shortcut method:


7   Launching events with attributes

When exiting a controller, it is possible to add attributes to the current event. To do that you need to generate an attribute map.

The controller which launches the event adds the attribute as follows:


8   Accessing the request context

If you want to invoke methods from classes other than controllers, like beans, it is possible to retrieve the web flow request context. There are two ways:

Passing the request context as a parameter to the bean method:

Or you can use the RequestContextHolder class:


9   Accessing Spring beans

If you need to retrieve beans from the Spring context, you can implement a utility class. The following method accesses the Spring context through the web flow request context.


10   Using implicit variables

There's a full list of all available implicit variables at the web flow reference documentation

springsource web flow reference (el-variables)


Tuesday, March 5, 2013

Centralize validation and exception handling with @ControllerAdvice



1 Introduction

The @ControllerAdvice annotation introduced by Spring 3.2 allows us to handle several functionalities in a way that can be shared by all controllers (through its handler methods, annotated with @RequestMapping). This annotation is mainly used to define the following methods:
  • @ExceptionHandler: Handles exceptions thrown by handler methods.
  • @InitBinder: Initializes the WebDataBinder, which will be used to populate objects passed as arguments to the handler methods. Usually, it is used to register property editors or validators.
  • @ModelAttribute: Binds a parameter or return value to an attribute, which will then be exposed to a web view.

Source code can be found at github.


2 Adding validation and exception handling

The following is a description of  the controller's handler methods before implementing the @ControllerAdvice.

Add person controller:

@RequestMapping(value="/persons", method=RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void addPerson(@Valid @RequestBody Person person, HttpServletRequest request, HttpServletResponse response) {
personRepository.addPerson(person);
logger.info("Person added: "+person.getId());
response.setHeader("Location", request.getRequestURL().append("/").append(person.getId()).toString());
}

@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(new PersonValidator());
}
      
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException pe) {
return new ResponseEntity<String>(pe.getMessage(), HttpStatus.BAD_REQUEST);
}


Besides the handler method, this controller has the following methods:
  • initBinder: Registers a validator to prevent that a person with invalid data is introduced. To make the validator validate the person object passed as a parameter, it is necessary to add the @Valid annotation to the argument. Spring 3 fully supports JSR-303 bean validation API, but it does not implement it. The reference implementation which is used in this example is Hibernate Validator 4.x.
  • handleValidationException: Handles the MethodArgumentNotValidException that can be thrown by the handler method. This exception is thrown by Spring MVC when an argument annotated with @Valid, fails its validation.


Get person controller:

@RequestMapping(value="/persons/{personId}", method=RequestMethod.GET)
public @ResponseBody Person getPerson(@PathVariable("personId") long id) {
return personRepository.getPerson(id);
}
     
@ExceptionHandler({PersonNotFoundException.class})
public ResponseEntity<String> handlePersonNotFound(PersonNotFoundException pe) {
return new ResponseEntity<String>(pe.getMessage(), HttpStatus.NOT_FOUND);
}
      

This controller adds an exception handler for handling when a request asks to retrieve a person that does not exist.





Update person controller:

@RequestMapping(value="/persons", method=RequestMethod.PUT)
@ResponseStatus(HttpStatus.CREATED)
public void updatePerson(@Valid @RequestBody Person person, HttpServletRequest request, HttpServletResponse response) {
personRepository.updatePerson(person);
logger.info("Person updated: "+person.getId());
response.setHeader("Location", request.getRequestURL().append("/").append(person.getId()).toString());
}
      
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(new PersonValidator());
}
      
@ExceptionHandler({PersonNotFoundException.class})
public ResponseEntity<String> handlePersonNotFound(PersonNotFoundException pe) {
return new ResponseEntity<String>(pe.getMessage(), HttpStatus.NOT_FOUND);
}
      
@ExceptionHandler({Exception.class})
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException pe) {
return new ResponseEntity<String>(pe.getMessage(), HttpStatus.BAD_REQUEST);
}
 
We are repeating code, since @ExceptionHandler is not global.


3 Centralizing code

@ControllerAdvice annotation is itself annotated with @Component, so the class that we are implementing will be autodetected through classpath scanning.

@ControllerAdvice
public class CentralControllerHandler {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(new PersonValidator());
}
      
@ExceptionHandler({PersonNotFoundException.class})
public ResponseEntity<String> handlePersonNotFound(PersonNotFoundException pe) {
return new ResponseEntity<String>(pe.getMessage(), HttpStatus.NOT_FOUND);
}
      
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException pe) {
return new ResponseEntity<String>(pe.getMessage(), HttpStatus.BAD_REQUEST);
}
}

Now we can delete these methods from the controllers, taking rid of code duplication, since this class will handle exception handling and validation for all handler methods annotated with @RequestMapping.

 

4 Testing

The methods described below, test the retrieval of persons:

@Test
public void getExistingPerson() {
String uri = "http://localhost:8081/rest-controlleradvice/spring/persons/{personId}";
Person person = restTemplate.getForObject(uri, Person.class, 1l);
assertNotNull(person);
assertEquals("Xavi", person.getName());
}
      
@Test
public void getNonExistingPerson() {
String uri = "http://localhost:8081/rest-controlleradvice/spring/persons/{personId}";
try {
restTemplate.getForObject(uri, Person.class, 5l);
throw new AssertionError("Should have returned an 404 error code");
} catch (HttpClientErrorException e) {
assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode());
}
}


The rest of tests can be found with the source code linked above.