Issue
have a spring boot/jpa application. In the code below - if the save call in createEntity() method raises a DataIntegrityViolationException, the exception is caught in the EntityExceptionHandler - not in the catch (of the try-catch) block. If the @Transactional annotation is removed from the createEntity method (service class), the DataIntegrityViolationException is caught in the catch block not in the exception handler.
Could this be explained? I don't understand the inconsistency.
Also if a try-catch block is placed around the createEntity call in EntityController, the exception is caught in the catch block - not in the exception handler - irrespective of whether the @Transactional annotation is set. Could this be explained also?
Thank you.
public class EntityController {
@PostMapping(value = "/entities")
@ResponseBody
public ResponseEntity postEntity(@RequestBody entity) {
entityService.createEntity(entity);
return ResponseEntity.status(HttpStatus.CREATED)...;
}
}
@Repository("EntityRepository")
public interface EntityRepository extends JpaRepository<Entity, UUID> {}
@Service
public class EntityServiceImpl implements EntityService {
@Autowired
private EntityRepository entityRepository;
@Override
@Transactional
public void createEntity() {
Entity entity = new Entity(...);
try {
entityRepository.save(entity);
} catch (DataIntegrityViolationException ex) {...}
}
}
@ControllerAdvice
public class EntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(DataIntegrityViolationException.class)
@ResponseBody
public ResponseEntity<Object> handleDataIntegrityViolationException(DataIntegrityViolationException ex, WebRequest request) {
return ResponseEntity.status(HttpStatus.CONFLICT).headers(new HttpHeaders()).body("");
}
}
Solution
The exception happens as soon as the transaction is submitted to the database. If the method is annotated with @Transactional, the submit happens in the "wrapper" and not within the createEntity method itself. Therefore the try-catch block has no effect.
Pseudocode with @Transactional:
beginTransaction()
try {
entityRepository.save(...)
} catch (....) {}
endTransaction() <- here the exception is thrown
Answered By - Martin Theiss
Answer Checked By - Timothy Miller (JavaFixing Admin)