Best practices for exception in my DAO layer - java

I'm working on my dao layer implementation and I'm confused about the exception handling part. I have many solution to throw exception so what is the best solution to handle exception in dao layer :
This is my code :
My DAO Interface :
#Repository
#Transactional
public interface GnqstRepository<T,V> {
public T save(T t);
public void delete(V v)throws GnqstRepositoryNotFoundException;
public T update(T t);
public T find(V v)throws GnqstRepositoryNotFoundException;
public List<T> findAll();
}
And this is my this an implementation for an entity :
public class EnqueteurRepository implements GnqstRepository<Enqueteur, Long> {
#PersistenceContext(name="gnst")
private EntityManager em ;
private static final Logger logger = Logger.getLogger(EnqueteurRepository.class);
#Override
public Enqueteur find(Long v)throws GnqstRepositoryNotFoundException {
Enqueteur enqueteur = em.find(Enqueteur.class,v);
if(enqueteur!= null){
logger.info("EnqueteurRepository : l'enqueteur avec l'ID : "+v+" a été trouvé avec succès.");
return enqueteur;
}
else{
throw new GnqstRepositoryNotFoundException("L'identifiant entré ne ressemble pas à un ID enqueteur valide.");
}
}
}
Here I create a checked exception my question is there best way than this to throw an exception to the next layer in case for example the find method do not find an entity ?
My objectif is that the user in IHM when click in button find for search in case of no result found then a message should show in IHM in my case I throw exception with a message throught dao layer,business layer to presentation layer my question is who is the best throw an exception or return null to the presentation layer then check an return message to the user ?Thank in advance

There are no hard and fast rules regarding exception handling, but these are my recommendations:
You have to ask yourself what the users of your repository would like to do when they do a lookup with a missing id.
If they want to take immediate action - for instance use a fallback repo - I would simply return a value representing "miss", such as null or Optional.empty().
If you want the error to propagate several layers up your application and maybe render a 404 or abort the running program, I would use an exception.
If you don't want to handle exceptions from different repositories differently, I would just stick with the standard EntityNotFoundException. If you do want to handle them differently I would introduce my own RuntimeExceptions.
Checked exceptions are quite rarely used today. They exist in the borderland between returning values representing failures and throwing exceptions. I believe that the consensus in the community is that they sound like a good idea but are bad in practice. So I would avoid them.

What's wrong with javax.persistence.EntityNotFoundException? This is a matter of debate, but if I were you I would keep close to JPA and avoid adding custom exceptions. I would also avoid changing the behaviour. In JPA the find method returns null if an entity is missing. Users of your find method may find it confusing to get an exception instead. I would return null or rename the method to findRequired.

I din't it's better to throw the Exception in the next layer. And you could simply return an Optional on this method:
public class EnqueteurRepository implements GnqstRepository<Enqueteur, Long> {
#PersistenceContext(name="gnst")
private EntityManager em ;
#Override
public Optional<Enqueteur> find(Long v) {
return Optional.ofNullable(em.find(Enqueteur.class,v));
}
}
And then, could throw a custom exception in the next layer.
void methodCallingDao() {
Optional<Enqueteur> enqueteur = enqueteurRepository.find(new Long(1));
if(!enqueteur.isPresent()) {
throw new RuntimeException("Error retrieving enqueteur");
}
}

Related

Spring Webflux - Proper way to throw checked custom exception (not RuntimeException)

May I ask what is the proper way to throw checked custom exception in Spring webflux please?
I would like to insist, it is about checked custom exception, like MyException.java, not something like RuntimeException, and it is about throwing exception, not handling exception.
I tried the following :
#Controller
#SpringBootApplication
public class QuestionHowToThrowException {
public static void main(String[] args) {
SpringApplication.run(QuestionHowToThrowException.class);
}
#PostMapping(path = "/question", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<ResponseEntity<QuestionResponse>> question(#RequestBody QuestionRequest questionRequest) {
Mono<FirstStep> firstStepMono = WebClient.create().post().uri("http://firstWebService:8111/getFirstStep")
.body(questionRequest.getThing(), String.class).retrieve().bodyToMono(FirstStep.class);
Mono<SecondStep> secondStepMono = firstStepMono.map(oneFirstStep -> getSecondStepFromFirstStepAfterCheck(oneFirstStep));
return secondStepMono.map(oneSecondStep -> ResponseEntity.ok(new QuestionResponse(oneSecondStep.getSecondThing())));
}
private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException {
if (firstStep.getThingNeedsToCheckCanThrowException().equals("exception")) {
throw new MyException("exception");
} else {
return new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good");
}
}
public class QuestionRequest {
private String thing;
public String getThing() {
return thing;
}
}
public class QuestionResponse {
private String response;
public QuestionResponse(String response) {
this.response = response;
}
}
public class FirstStep {
private String thingNeedsToCheckCanThrowException;
public String getThingNeedsToCheckCanThrowException() {
return thingNeedsToCheckCanThrowException;
}
}
public class SecondStep {
private String secondThing;
public SecondStep(String secondThing) {
this.secondThing = secondThing;
}
public String getSecondThing() {
return secondThing;
}
}
}
This is not possible, since there in an unhandled exception in getSecondStepFromFirstStepAfterCheck method.
If I throw and propagate, private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException the lambda caller method is not happy.
What is the cleanest and proper way to throw custom exception in webflux please?
Thank you
Reading through your sample code, it looks like you are trying to introduce some error handling with on your Mono.
You can create an unchecked exception by extending the RuntimeException class. If you want a checked exception that enforces handling, you can simply extend Exception.
public class MyException extends RuntimeException {
public MyException(String msg) {
super(s);
}
}
The cleanest way to throw an exception with the Reactor project is really just to throw it. There are error handling functions that allow you to provide different flows to certain error cases.
The good news is you have several options that provides some flow control for error handling.
Project Reactor provides several of these methods on the Mono object.
doOnError(),onErrorContinue(),onErrorReturn(),onErrorStop(),onErrorMap()
I am not entirely sure what you are trying to achieve with the following sample code.
return Mono.error(new MyException("exception"));
} else {
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good"));
But this looks like a good case for a onErrorMap() since it looks like you are trying to translate some exception here
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good")
.onErrorMap(e -> "translated result");
For our applications, we have our custom base exception extend from RuntimeException. We then have standard exception handling that looks for our custom exception for special handling before returning results back to the end user. This allows us to use normal throws mechanics since we want all exceptions thrown to ripple up the top level of the call.
For performance concerns webflux and reactive are slightly lower performance on a per call basis especially for calls that don't need to do any parallelization. However once load is put onto the system it tends to become more performant primarily related to garbage collection. Overhead from the difference between map and flatMap should be negligible at best.

Delete Mapping Exception in Spring Data

Hello i would like to throw an exception in case the user enters an id that is not existing in the system.
This is my mapping
#DeleteMapping("/drugs/{neo4jId}")
public void deleteDrug(#PathVariable Long neo4jId) {
drugsRep.deleteById(neo4jId);
}
what would you suggest?
* I dont want to handle it only in my Frontend
You can try something like this:
if (drugsRep.existsById(neo4jId)) {
throw new EntityNotFoundExceptionById("Invlaid Id was provided");
}
drugsRep.deleteById(neo4jId);
If you define a custom exception you can map it to appropriate http status.
#ResponseStatus(HttpStatus.NOT_FOUND)
public class EntityNotFoundExceptionById extends RuntimeException {
public EntityNotFoundExceptionById(String message) {
super(message);
}
}
Good morning, in this case you can check if user exists.
In Spring-mongodb have one function when you extends the MongoRepository with the name of existsById. So take a look in the documentation, maybe your repository have this function too.
And, when you use this function you can throw one exception. Like the code
if(!repository.existsById(id)){
throw new NotFoundException();
}
repository.deleteById(id);

What Dropwizard-Hibernate doc is trying to say?

I have run into LazyInitializationException and then I ran into the following paragraph from the official doc. Unfortunately, it makes absolutely no sense to me. Please help.
(The code block above the paragraph in the doc.)
#GET
#Timed
#UnitOfWork
public Person findPerson(#PathParam("id") LongParam id) {
return dao.findById(id.get());
}
Important
The Hibernate session is closed before your resource method’s return
value (e.g., the Person from the database), which means your resource
method (or DAO) is responsible for initializing all lazily-loaded
collections, etc., before returning. Otherwise, you’ll get a
LazyInitializationException thrown in your template (or null values
produced by Jackson).
First The Hibernate session is closed before your resource method’s return value. How is this possible? This would have been possible had there been a try-finally block around my resource's return statement, but that is not the case here.
My resource should have been invoked by another method, which I am guessing would open the Hibernate session before my resource method is invoked and would then close the session after my resource method returns. How can it close it before my method returns. I don't get it.
The most important part - which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. I have no Hibernate experience. I am using it for the first time now. How do I initialize, or rather what is exactly is meant by "initialize" in context of Hibernate? A code example will help a lot.
PS: This question might look odd, and someone at a cursory glance might even suggest to move it to "English Language and Usage", but please read it carefully. This is a technical question, not paragraph dissection.
Edit:
Added the code block from the doc else it won't make sense anyone. Also I removed one paragraph from my question, which became clear to me, immediately after posting the question.
First The Hibernate session is closed before your resource method’s
return value. How is this possible? This would have been possible had
there been a try-finally block around my resource's return statement,
but that is not the case here.
I know nothing about Dropwizard. So let's see the source (I change it a bit).
From UnitOfWorkAwareProxyFactory
class UnitOfWorkAwareProxyFactory {
public <T> T create(Class<T> clazz) {
final ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(clazz);
final Proxy proxy = (Proxy) factory.createClass().newInstance();
proxy.setHandler(new MethodHandler() {
#Override
public Object invoke(Object self, Method overridden,
Method proceed, Object[] args) {
final UnitOfWork unitOfWork = overridden.getAnnotation(UnitOfWork.class);
final UnitOfWorkAspect unitOfWorkAspect = new UnitOfWorkAspect(sessionFactories);
try {
unitOfWorkAspect.beforeStart(unitOfWork);
Object result = proceed.invoke(self, args);
unitOfWorkAspect.afterEnd();
return result;
} catch (Exception e) {
unitOfWorkAspect.onError();
throw e;
}
}
});
return (T) proxy;
}
}
if you have a class
class PersonDao {
#UnitOfWork
public Person findPerson(LongParam id) {
return dao.findById(id.get());
}
}
You can do something like this
UnitOfWorkAwareProxyFactory factory = new UnitOfWorkAwareProxyFactory();
PersonDao proxy = factory.create(PersonDao.class);
when you do
Person person = proxy.findPerson(1L);
that line becomes
unitOfWorkAspect.beforeStart(unitOfWork);
Object result = findPerson.invoke(proxy, 1L);
unitOfWorkAspect.afterEnd();
return result;
Methods unitOfWorkAspect.beforeStart(unitOfWork) and unitOfWorkAspect.afterEnd() from the source UnitOfWorkAspect
class UnitOfWorkAspect {
public void beforeStart(UnitOfWork unitOfWork) {
session = sessionFactory.openSession();
configureSession();
beginTransaction();
}
public void afterEnd() {
try {
commitTransaction();
} catch (Exception e) {
rollbackTransaction();
throw e;
} finally {
session.close();
}
}
}
The most important part - which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. I have no Hibernate experience. I am using it for the first time now. How do I initialize, or rather what is exactly is meant by "initialize" in context of Hibernate?
Initialize in this context means the collection data should be loaded from a database. Some methods of an initialization
1.Use an eager loading, for an example
class User {
#ManyToMany(fetch = FetchType.EAGER)
private List<Role> roles;
}
Hibernate will load roles via joins or subselects, when you get a User entity.
Use Hibernate.initialize(user.getRoles())
Use join fetch in HQL — from User user left join fetch user.roles
Use Criteria with setFetchMode()
Use fetch profiles, entity graphs. Don't know can entity graphs be used with a session, it is a JPA feature: http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/fetching/Fetching.html
If you don't need to fetch collections, you can use a partial objects loading with transforming to the root entity: How to transform a flat result set using Hibernate

Global Exception Handling in Jersey & Spring?

I am developing the RESTful webservices using Jersey & Spring 3.2 along with Open CMIS.
I am not using MVC pattern of Spring and it's just Spring IOC & Jersey SpringServlet, the controller class is something like below code
#GET
#Path("/{objId:.+}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public statusMsg addObject(#PathParam("objId") String objId{
return repoService.addObject(objId);
}
In the repoService I am performing the business logic to add the object using CMIS, my question is that I am catching around 5 exceptions related to CMIS then the base exception i.e Exception but for every service method I have to repeat it which I don't want to do.
I was searching on Google and found that #ControllerAdvice is the best solution for such problem wheer you can define all the checked & unchecked exceptions and wherever remove all the try catch blocks from the application. But it only work with MVC pattern.
Question 1: Is there a way I can use this in above Jersey-Spring framework?
After more reserach I found that Jersey provides ExceptionMapper to handle customized exception but I want to catch more CMIS exception or default Exception or IO Exception etc.
Question 2: How can I do it with ExceptionMapper?
Question 3: Am I on the correct approach or do you suggest any better approach to handle such issues.
Thanks in advance.
I use jersey2.11 with Tomcat and almost exception handle with ExceptionMapper.
(In domain logic, only DB rollback process use try-catch code.)
I think ExceptionMapper with #Provider automatically choose correct ExceptionMapper. So I suppose this function is satisfied with "I want to catch more CMIS exception or default Exception or IO Exception etc."
This code is my handling ExceptionMapper design code.
1.Some Jersey Root Resource Class
#GET
#Produces("application/json")
public String getUser(#NotNull #QueryParam("id") String id,
#NotNull #QueryParam("token") String token) throws Exception { // This level throws exceptions handled by ExceptionMapper
someComplexMethod(id, token); // possible throw Exception, IOException or other exceptions.
return CLICHED_MESSAGE;
}
2.ExceptionMapper package. com.yourdomain.exceptionmapper
AbstractExceptionMapper.java (All ExceptionMapper class extends this Abstract class)
public abstract class AbstractExceptionMapper {
private static Logger logger = LogManager.getLogger(); // Example log4j2.
protected Response errorResponse(int status, ResponseEntity responseEntity) {
return customizeResponse(status, responseEntity);
}
protected Response errorResponse(int status, ResponseEntity responseEntity, Throwable t) {
logger.catching(t); // logging stack trace.
return customizeResponse(status, responseEntity);
}
private Response customizeResponse(int status, ResponseEntity responseEntity) {
return Response.status(status).entity(responseEntity).build();
}
}
ExceptionMapper.java (At least this mapper can catch any exception which is not define specify exception mapper.)
#Provider
public class ExceptionMapper extends AbstractExceptionMapper implements
javax.ws.rs.ext.ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
// ResponseEntity class's Member Integer code, String message, Object data. For response format.
ResponseEntity re = new ResponseEntity(Code.ERROR_MISC);
return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
}
}
WebApplicationExceptionMapper.java (Specify WebApplicationException)
#Provider
public class WebApplicationExceptionMapper extends AbstractExceptionMapper implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException e) {
ResponseEntity re = new ResponseEntity(Code.ERROR_WEB_APPLICATION);
return this.errorResponse(e.getResponse().getStatus(), re, e);
}
}
ConstraintViolationExceptionMapper.java (Specify Hibernate Validator ConstraintViolationException)
#Provider
public class ConstraintViolationExceptionMapper extends AbstractExceptionMapper implements
ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException e) {
ResponseEntity re = new ResponseEntity(Code.ERROR_CONSTRAINT_VIOLATION);
List<Map<String, ?>> data = new ArrayList<>();
Map<String, String> errorMap;
for (final ConstraintViolation<?> error : e.getConstraintViolations()) {
errorMap = new HashMap<>();
errorMap.put("attribute", error.getPropertyPath().toString());
errorMap.put("message", error.getMessage());
data.add(errorMap);
}
re.setData(data);
return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
}
}
.. and other specify exception can create ExceptionMapper classes.
In my experience, Exception Mapper is high level idea for focus to domain logic. It could drive out boring scattered try-catch block code from domain logic.
So I hope that you feel the "Yes i am" at Question 3 to resolve the problem at your environment.
you have not used try catch and throw anywhere across the application.
My code design use throws at method like this and this make to manage by ExceptionMapper classes.
public String getUser(#NotNull #QueryParam("id") String id,
#NotNull #QueryParam("token") String token) throws Exception
So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.
Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.
Q.2. Do you foresee any issue in above approach.
I think if simple project or never update/modify project (project lifecycle short time), your one class exception mapper approach ok.
But ... i never take this approach. Simply, if need to manage more exception, this method become big and complex, and hard to read and maintain becoming.
In my policy, OOP should use pleomorphism strategy any level code(class plan, DI plan) and this approach some part aim to drive out if/switch block in code. And this idea make each method short code and simple, clear to "domain logic" and code become to resistant to modify.
So i create implements ExceptionMapper and delegate to DI which ExceptionMapper class manage to exception.
(So DI manage replace your single class If block manage which exception handling, this is typically refactoring approach similar Extract xxx http://refactoring.com/catalog/extractClass.html.
In our discussion case, single class and one method too busy, so extract each ExceptionMapper class approaching and DI call suitable class & method strategy.)
Btw, system processing result is same at present point. But if need to reduce future development cost ,should not took approach one class exception handling plan. Because if give up simply code and refactor status, project code is dead faster.
This is my idea and why this.
regards.
thanks for your reply. I can see you have created multiple classes based on the exception type and behaviour.
Q1. In your services method are you throwing any exception like
public void addObject(String objId) throws WebApplicationException{
}
or you have not used try catch and throw anywhere across the application.
Actually, I have tried something where in my web application I am not using try, catch and throws anywhere and in my CentralControllerException I have mentioned like below:
public class CentralControllerHandler implements ExceptionMapper<Exception> {
#Override
#Produces(MediaType.APPLICATION_JSON)
public Response toResponse(Exception ex) {
if(ex instanceof CmisContentAlreadyExistsException){
log.error(ex);
// send Response status as 400
}
if(ex instanceof IOException){
log.error(ex);
// send Response status as 400
}
return Response;
}
}
So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.
Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.
Q.2. Do you foresee any issue in above approach.

Writing a database logger from Play - how to handle errors?

I'm writing a database log4j appender in Play.
On its append() method, it creates a new instance of a model entity Log4jLine, and saves() it via JPA.
This works fine on debug/info logs. However, exceptions are not logged.
There is a call to this appender from framework code, but I suspect it is not working because the JPA session is not valid at this point.
How would I adapt the code to support this use case?
public class DBAppender extends AppenderSkeleton {
#Override
protected void append(LoggingEvent loggingEvent) {
Log4jLine logLine = new Log4jLine(...);
logLine.save();
}
}
Per our conversation above I was curious about how to do this and was able to get this to work. Essentially, you need to create a new EntityManager and fully manage it yourself. Calling any of the Play built-ins (.save(), .merge(), etc) will cause them to use the EntityManager that Play sets up for you. However, if you revert to standard JPA calls, it will work.
// Mapped in routes file as GET /exception
public static void exceptionTest() {
RuntimeException e = new RuntimeException("This is a test");
logException(e);
renderText("You are here");
}
private static void logException(RuntimeException e) {
EntityManager em = JPA.newEntityManager();
Notification n = new Notification();
n.setMessage(e.getMessage());
em.getTransaction().begin();
em.persist(n);
em.getTransaction().commit();
throw e;
}
This is just a quick and dirty experiment to prove the point. You'll obviously need to handle exceptions and failure cases in logException() that I'm not handling. And just for clarity, Notification is a basic object in my project I was able to use for this quickly.
Hope that helps!

Categories