Spring Framework – how to execute some code only after successful commit

Sitewide-10dollars300x250 When coding a Spring application, we will typically be annotating our service methods with @Tansactional, and sometimes we would want to execute come code only if the transaction succeeds. For example, when a user signs up, she should receive a verification mail only if her record is successfully committed to the database.

Precisely, a signup process can flow as below:

  1. Our signup controller receives a signup request
  2. It calls a service method for doing the job
  3. A transaction begins
  4. The service method
    1. saves the new user to the database
    2. sends a verification mail to the user
    3. exits
  5. The transaction tries to commit, FAILS for some reason, and rolls back!
  6. The controller receives the exception and passes it to the client
  7. The user sees that she was unable to sign up
  8. She still gets a verification mail!

Actually, we should execute 4.2 only if the transaction succeeds. Otherwise the user will get a verification mail even if the signup fails!

A way to tell Spring to run such code only after the transaction succeeds is to put the code in the afterCommit method of a TransactionSynchronizationAdapter object, and register the object.

Precisely, we should code 4.2 like this:


TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            // code for sending verification mail
        }
});

This is heavy boilerplate code. Using Java 8, we can encapsulate it into a utility method, as below:


public static void afterCommit(Runnable runnable) {
    TransactionSynchronizationManager.registerSynchronization(
        new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                runnable.run();
            }
    });
}

afterCommit can then be used as below:


afterCommit(() -> {
    // code for sending verification mail
});

If you found it helpful, you may like our Spring Framework 4 for the Real World – Beginner to Expert course, which covers many such essential real-world use cases in details!

Using domain classes instead of command objects and DTOs

Sitewide-10dollars300x250 A common practice to pass data in and out of a Spring application is to use command objects and DTOs. For example, when coding a REST API, we usually receive the parameters in a POJO (which is historically called a command object), copy the data into a domain entity to save it to the database, and finally copy the output data onto another POJO (which we call a DTO) and send that back to the client.

In this blog post, I’m going to discuss a more elegant way – reusing the domain entities for everything. No command classes, no DTOs, no copying. I’ll be discussing it in reference to a Spring Boot application, but it should be well applicable to all kinds of applications.

So, let’s see how to use domain entities for everything!

1) Switch-off JPA persistence validation

To validate user inputs, mostly we would use JSR-303 annotations, such as @Size(max=30). That means, apart from JPA annotations, our entity fields would need to be annotated with these annotations as well, e.g.:

	@Column(nullable = false) // a database constraint
	@Size(min=6) // a validation constraint
	private String password;

This would – by default – lead JPA to run the validations again, before saving to the database.

You may like to switch off this redundant validation. To do so, in a Spring Boot application, just put this line in your application.properties:

spring.jpa.properties.javax.persistence.validation.mode: none

2) Receive only needed input parameters

Your controller method for receiving input parameters may look as below:

@PostMapping
public DomainEntity save(DomainEntity entity) {

    repository.save(entity);
    return entity;
}

See a security loophole here?

Your entity may be having more fields than just the input parameters. So, a malicious user can add those undesired fields in his input, and that data goes to the database! To prevent this, you can use JsonViews. Precisely,

  1. Annotate the input fields with @JsonView
  2. Annotate the entity parameter in the controller method with @JsonView

In summary, your domain class may look as below:

@Entity
public class DomainEntity {

   public static interface In {}

   ...

   @JsonView(In.class)
   @Column(nullable = false) // a database constraint
   @Size(min=6) // a validation constraint
   private String password;

   ...
}

And, your controller would look as below:

@PostMapping
public DomainEntity save(@JsonView(In.class) DomainEntity entity) {

    repository.save(entity);
    return entity;
}

In is just a marker interface.

Return only needed fields

Similarly, you wouldn’t like to return all the fields back to the user. To restrict the output fields, annotate the desired ones with @JsonView, as below:

@Entity
public class DomainEntity {

   public static interface In {}
   public static interface Out {}

   ...

   @JsonView(Out.class)
   private String anOutField;
   ...
}

And, annotate the controller method as well with @JsonView, as below:

@JsonView(Out.class)
@PostMapping
public DomainEntity save(@JsonView(In.class) DomainEntity entity) {

    repository.save(entity);
    return entity;
}

Again, Out is just another marker interface.

But, what if a field should be both In as well as Out?

JsonView Inheritance

To include a field in both the In and Out operations, I think we can supply both the interfaces to its @JsonView annotation, as below:

    @JsonView({In.class, Out.class})
    private String anInOutField;

But, there is a better way. @JsonView recognizes view inheritance. So, you can just have a super InOut interface, as below:

    public static interface InOut {}
    public static interface Out extends InOut {}
    public static interface In extends InOut {}

And the, you can use the InOut interface for all the in-out fields:

    @JsonView(InOut.class)
    private String anInOutField;

Using the same domain class in multiple controllers

Finally, you may be having multiple controller methods using the same domain entity, e.g., one for creation and another for updating. That may need us to have more view interfaces, and use some more complex inheritance.

For different validation requirements of different controller methods, you can use constraint groups, which is covered more elaborately in our Spring Framework 4 for the Real World – Beginner to Expert course, and discussed briefly in this blog post.

Looks complex? Believe me, it’s not in most cases! Just try it out and you would appreciate it.

Spring Boot 1.4 released – Spring Tutorial updated

Sitewide-10dollars300x250 Spring Boot 1.4 just got released. It now comes with Spring 4.3 and Spring Security 4.1 updates, and so with some cool features.

We have already updated our books – those now use Spring Boot 1.4. In this post, for the readers that already have gone through the 1.3 version of the books, let’s brief the changes we have done to the books and the underlying code.

Removed @Autowired from constructors

It is no longer necessary to specify the @Autowired annotation if the target bean only defines one constructor.

Replaced @RequestMapping with @GetMapping, @PostMapping etc.

Spring Framework 4.3 comes with @GetMapping, @PostMapping, @PutMapping, @DeleteMapping and @PatchMapping variants of the @RequestMapping annotation that you can now use. See here for more details.

Replaced @ControllerAdvice with @RestControllerAdvice

Spring Framework 4.3 comes with a @RestControllerAdvice. So, in our Module III, we replaced the @ControllerAdvice with @RestControllerAdvice.

Removed AuthenticationManagerBuilder configuration from security configuration

You can now define custom authentication by exposing a custom UserDetailsService as a bean. You can also customize how passwords are encoded by exposing a PasswordEncoder as a bean. So, configuring the AuthenticationManagerBuilder was no more needed. See here for details.

Replaced antMatchers with mvcMatchers

For securing request handlers, we were previously using antMatchers. Spring Security 4.1 comes with mvcMatchers, which is better to use. See here for details.

Introduced method security meta-annotations

You can make use of meta annotations for method security to make your code more readable, and we have introduced that in the Module III. Refer here for more details.

Updated testing configuration

In Module III, replaced previous testing annotations to the AbstractTests class with the simpler

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=RANDOM_PORT)
@ActiveProfiles("itest")

Also, now there is a meta annotation @LocalServerPort which replaced @Value("${local.server.port}") in AbstractTests.

Refer here for details.

Happy coding!