Using Vyncent help, here is the solution I came to. I created a new class called UserCreationService and put the whole method that handled the creation of User in this class. Here is an example:
@Override public User registerUserWithProfileData(User newUser, String password, Boolean waitForAccount) { newUser.setPassword(password); newUser.encodePassword(); newUser.setJoinDate(Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime()); User registered = userService.createUser(newUser); registered = userService.processNewRegistration(registered, waitForAccount); return userService.setProfileInformation(registered); }
You will notice that there is an annotation NO @Transactional in this method. This is special. The corresponding definitions of createUser and processNewRegistration are as follows:
@Override @Transactional(propagation = Propagation.REQUIRES_NEW) public User createUser(User newUser) { String username = newUser.getUsername(); String email = newUser.getEmail(); if ((username != null) && (userDAO.getUserByUsername(username) != null)) { throw new EntityAlreadyExistsException("User already registered: " + username); } if (userDAO.getUserByUsername(newUser.getEmail()) != null) { throw new EntityAlreadyExistsException("User already registered: " + email); } return userDAO.merge(newUser); } @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public User processNewRegistration( User newUser, Boolean waitForAccount) { Future<UserAccount> customer = paymentService.initializeForNewUser(newUser); if (waitForAccount) { try { customer.get(); } catch (Exception e) { logger.error("Error while creating Customer object!", e); } }
Vyncent was a stain on the fact that transaction management was a problem. Creating another service allowed me to better control when these transactions take place. While I was unable to take this approach initially, this is a compromise with Spring-driven transactions and proxies.
I hope this helps someone else save some time later.
source share