Auditing in Spring Data JPA JavaConfig

In addition to the reference documentation of spring data jpa auditing. This is my interpretation of how to implement auditing and auditor aware in spring applications using JavaConfig. Please note that this requires having version 1.5.0.RELEASE or greater.

First, I created a base abstract class for entities which will hold definitions for created, last modified by and created, last modified by date. These can be described by using annotations @CreatedBy, @LastModifiedBy, @CreatedDate, and @LastModifiedDate. In this case I used joda time to define the type of date. The reference documentation also mentions adding AuditingEntityListener to the orm.xml file, however, if you wish to not include a xml file, you can add @EntityListeners(AuditingEntityListener.class) annotation to the abstract entity class. Here is an example:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AbstractEntity {

    @CreatedDate
    @NotNull
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime createdDate = DateTime.now();

    @LastModifiedDate
    @NotNull
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime lastModifiedDate = DateTime.now();

    @CreatedBy
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    @NotNull
    private Account createdBy;

    @LastModifiedBy
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    @NotNull
    private Account lastModifiedBy;

    ...
}

For created by and last modified by to be filled in with spring security principal information you use the AuitorAware<T> interface. Here is an example calling the account service to gain access for the current account information. The @Component annotation was used so a bean definition did not need to be defined in the configuration class which was suggested in the reference documentation.

@Component
public class SpringSecurityAuditorAware implements AuditorAware<Account> {

    @Inject private AccountService service;

    @Override
    public Account getCurrentAuditor() {
        return service.getCurrentAccount();
    }

}
@Override
public Account getCurrentAccount() {
    SecurityContext securityContext = SecurityContextHolder.getContext();
    UserDetailsCustom springSecurityUser = (UserDetailsCustom) securityContext.getAuthentication().getPrincipal();
    return springSecurityUser.getAccount();
}

Finally, add the annotation @EnableJpaAuditing to have the configuration be loaded. Also be sure to add jadira.usertype.databaseZone to the hibernation configuration (in this case) to set the timezone for joda time.

@Configuration
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
...
public class DataBaseConfig { }

Testing Implementation for Integration Tests

If you care about testing (and you should), here are some tips one getting auditing working with your integration tests. First, create a new component for a mock auditor aware class. This will allow for auditing without the need for spring security.

@Component
public class MockAuditorAware implements AuditorAware<Account> {

    private Account currentAuditor;

    @Override
    public Account getCurrentAuditor() { return currentAuditor; }
    public void setCurrentAuditor(Account account) {this.currentAuditor = account; }

}

Be sure to add the mock auditor aware reference in the test configuration class.

@Configuration
@EnableJpaAuditing(auditorAwareRef = "mockAuditorAware")
...
public class TestConfig { }

Finally, in a base integrations test class, you can add a before statement for setting the auditor for all your tests:

@PersistenceContext protected EntityManager em;
@Inject protected MockAuditorAware auditorAware;

@Before
public void wireUpAuditor() {
    auditorAware.setCurrentAuditor(em.getReference(Account.class, 1));
}