Spring 4.3 recap for API-centric apps

The Spring framework is the most widely adopted open source project in enterprise class applications. As the framework consists of dozens of modules, every team is interested only in a subset of changes introduces in the latest release. This post covers the list of new features that shouldn’t be missed by any developer whose application’s API relies on Spring 4 and is preparing for the upgrade in the foreseeable future.

Advertisement

1. Specialized request mappings

The @RequestMapping annotation was introduced in Spring 2.5 and since then it is the hallmark of the Spring web development process. Even though the annotation defines several attributes, path and method attributes seems to be the most frequently used and since the latter is a finite list of values Spring 4.3 brings specialized mapping annotation variants for each HTTP method. Let’s have a look at the following example:

@RestController
@RequestMapping("/tasks")
public class TaskController {

    private TaskService taskService;

    public TaskController(TaskService taskService) {
        this.taskService = taskService;
    }

    @GetMapping
    public Collection<Task> listTasks() {
        return taskService.findAll();
    }

    @PostMapping
    public void queueNewTask(@RequestBody Task task) {
        taskService.add(task);
    }

    @DeleteMapping("/{taskId}")
    public void dequeueTask(@PathVariable long taskId) {
        taskService.delete(taskId);
    }

}

As API-centric applications are very popular nowadays the new set of annotations will definitely save developers some repetitive typing. Does it mean that we should bid farewell to @RequestMapping? Of course not. It is still genuinely useful as a class level annotation that groups several operations with a common URL prefix.

2. Specialized life cycle scopes

Spring 4.3 also brings replacement for the @Scope annotation. Instead of writing the type of the scope as a String value attribute, each scope has a corresponding annotation: @RequestScope, @SessionScope, and @ApplicationScope. This small change will definitely save some frustrations caused by typos in the scope names and suppresses messages like the one below from appearing again.

java.lang.IllegalStateException: No Scope registered for scope name 'reqest'

3. New @RestControllerAdvice and updated @ResponseStatus

If you have ever ran into a situation where you repeated @ResponseBody annotation on each method in your controller advice and thought “Why can’t it be as easy as with @RestController?”, you will be pleased to see a brand new annotation called @RestControllerAdvice which does exactly what you desired.

@RestControllerAdvice
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ValidationResponse handle(MethodArgumentNotValidException e) {
        return new ValidationResponse(e);
    }

    @ExceptionHandler(CustomAppException.class)
    public AppErrorResponse handle(CustomAppException e) {
        return new AppErrorResponse(e);
    }

}

@RestControllerAdvice goes well with a change introduced to the @ReponseStatus annotation which according to the release notes is “now supported at the class level and inherited by all methods”. This statement isn’t entirely true as the definition of the annotation allowed it to be used at the class level before Spring 4.3 (@Target({ElementType.TYPE, ElementType.METHOD}). Unfortunately, the defined status code wasn’t applied to all methods in the class which lead to ambiguity. From now it works as expected.

4. Out of the box support for HTTP HEAD

There is no need to mark request mappings with the HEAD method anymore. Every request which supports the HTTP GET method automatically handles the HEAD request as well. Values of the three following headers are set by default:

  • Content-Type
  • Content-Length
  • Date

No matter whether the GET or HEAD option is used, the request mapping method is always executed. The only difference is that the GET handler returns the whole response body while the HEAD response is limited only to headers.

5. Implicit HTTP OPTIONS response

Another simplification introduces in Spring 4.3 is auto generation of an OPTIONS response, which sets the Allow header based on all request mappings for a given URL.  For example an OPTIONS request with the /tasks path for the TaskController from the first point returns:

Allow: POST,GET,HEAD

POST and GET come from @PostMapping and @GetMapping annotations. HEAD is implicitly generated for the GET handler as described in the previous point. The @DeleteMapping(“/{taskId}”) points to /tasks/{taskId} hence it’s not present in the response.

It’s worth reminding that if a request mapping doesn’t specify any HTTP methods, for instance @RequestMapping(“/somePath”), by default all methods are supported. In that case an OPTIONS response contains:

Allow: GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS

6. Constructor injection without @Autowired

If you had read closely the sample from the first point you probably have noticed the controller has a dependency on another bean specified in its constructor, but there is no @Autowired annotation. This isn’t a mistake. If a bean in Spring 4.3 defines only one constructor, it is automatically used for dependency injection. The rule also applies to values injected from application.properties.

@Service
public class SecretConsumer {

    private static final Logger log = LoggerFactory.getLogger(SecretConsumer.class);

    public SecretConsumer(@Value("${secret.key}") String secretKey) {
        log.info("The secret key {} has been successfully injected", secretKey);
    }

}

The battle between supporters of constructor injection and field injection probably will never end, but the Spring team is getting more and more opinionated about the subject and gently begins to suggest the first option.

Even if you were loyal to the constructor injection principal you couldn’t apply it to classes annotated with @Configuration. Spring 4.3 removed this constraint and now you can be consistent across the whole code base of your application. Just like in case of other components, if there is only one constructor, the @Autowired annotation can be omitted.

Conclusion

Spring 4.3 is all about simplification. Although described changes aren’t shocking and won’t turn the whole development process upside down, they will definitely facilitate mundane activities. Please bear in mind the presented list is just a small subset of all introduced changes. The full change log can be found in the official release notes.

Facebooktwittergoogle_plusredditlinkedinmail
Advertisement