spring-bootjpaspring-data-jpaauditing

Custom implementation of getCurrentAuditor method returns error when trying to use a JPA repository


I have a user entity with an audit field named lastUpdatedUserId (same as LastModifiedBy). This is an integer field. I'm trying to use the auditing feature provided by Spring and did everything stated in the docs. When I tried to override the getCurrentAuditor method of AuditorAware, it works fine if I hardcode an integer as the return value. If I try to use UserRepository (a Spring Data JPA repository) to get the user id of the logged in user, I get a Could not commit JPA transaction error. I'm using Gmail Oauth2 for authentication. The stacktrace is too long for me to post here. I tried to debug, but it has not been easy.

If any of you know the reason, please let me know.

@EntityListeners(AuditingEntityListener.class)
public class User {
    @LastModifiedBy
  @Column(name = "lst_updtd_usr_id")
  private Integer lastUpdatedUserId;
    ...
}

 public class AuditorAwareImpl implements AuditorAware<Integer> {
  
      @Autowired
      private UserRepository userRepo;
  
       @Override
       public Optional<Integer> getCurrentAuditor() {
        // your custom logic
      
      DefaultOidcUser oidcUser = (DefaultOidcUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String emailId = oidcUser.getEmail();
    User user = userRepo.findByEmailId(emailId);
      return Optional.of(user.getUserId());
       }

    }

 @Configuration 
 @EnableJpaAuditing(auditorAwareRef="auditorP")
    public class PersistenceConfig {

    @Bean
    AuditorAware<Integer> auditorP() {
        return new AuditorAwareImpl();
    }

   }

Solution

  • The population of auditing fields happens in JPA lifecycle events. When handling such events one is not allowed to use the EntityManager, which you do when you try to use a Spring Data JPA repository.

    As a workaround you could:

    1. Load the required version before the events get triggered and keep it in some request scope variable.
    2. Use JDBC directly to access the database to obtain the information.