I have this spring service:
@Service
@Transactional
public class ConsorcioServiceImpl implements ConsorcioService {
...
@Autowired
private ConsorcioRepository consorcioRepository;
@Override
public void saveBank(Consorcio consorcio) throws BusinessException {
try {
consorcioRepository.save(consorcio);
}
catch(DataIntegrityViolationException divex) {
if(divex.getMessage().contains("uq_codigo")) {
throw new DuplicatedCodeException(divex);
}
else {
throw new BusinessException(dives);
}
}
catch (Exception e) {
throw new BusinessException(e);
}
}
}
That service uses this Spring Data repository:
@Repository
public interface ConsorcioRepository extendsCrudRepository<Consorcio, Integer> {
}
I'm calling the service from a spring controller:
@Controller
@RequestMapping(value = "/bank")
public class BancaController {
@Autowired
private ConsorcioService consorcioService;
@RequestMapping(value="create", method=RequestMethod.POST)
public ModelAndView crearBanca(@Valid BancaViewModel bancaViewModel, BindingResult bindingResult,
RedirectAttributes redirectAttributes) {
ModelAndView modelAndView;
MessageViewModel result;
try {
consorcioService.saveBank(bancaViewModel.buildBanca());
result = new MessageViewModel(MessageType.SUCESS);
redirectAttributes.addFlashAttribute("messageViewModel", result);
modelAndView = new ModelAndView("redirect:/banca/crear");
return modelAndView;
} catch (Exception e) {
result = new MessageViewModel(MessageType.ERROR);
modelAndView = new ModelAndView("crear-bancas");
modelAndView.addObject("messageViewModel", result);
return modelAndView;
}
}
But the exception I get in the controller is: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
instead of the DuplicatedCodeException
I throw in the service. I need to identify the type of exception so I can give a custom friendly user message.
also your DuplicatedCodeException , BusinessException should be runtime exception , or add for method saveBank :
in other case spring will not rollback transaction.
from Spring documentation:
That happens because your exception is wrapped in
RollbackException
asThrowable
cause. In it's turnRollbackException
is also a cause ofTransactionSystemException
.You can build global exception handler to catch and customize all exceptions as you wish:
@ControllerAdvice
is available since Spring 3.2Also you can use
@ExceptionHandler
at the@Controller
level, or create this handling in abstract-controller if you have one as a super class of all your controllers.There are some other approaches, for full reference please follow the:
Spring IO: Exception handling in Spring MVC
Baeldung: Exception handling with Spring
Just add
catch (TransactionSystemException tse)
beforecatch (Exception e)
branch and then extract your exception withgetOriginalException()
.