EJB and persistence exception - java

By working with Java EE, I defined a persistence layer that exposes serval DAOs (extending GenericDAO and by using Hibernate as ORM).
Then, I inject a certail DAO in order to work with it into another class.
#Inject
private MyDAO myDAO;
public void writeSomething(String key, String data) {
try {
myDAO.create(key, data);
} catch (ConstraintViolationException e) {
// BLOCK 1
} catch (Exception e) {
// BLOCK 2
}
}
Now, I'd like to test exceptions, by trying to write an entry duplication.
As expected, the application returns an error, but it isn't a ConstraintViolationException instance, but something else (in fact, EJBException).
11:42:19,065 ERROR [org.jboss.ejb3.invocation] (http-localhost-127.0.0.1-8080-3) JBAS014134: EJB Invocation failed on component MyDAO for method public java.lang.Object my.app.dal.genericdao.GenericDAOImpl.create(java.lang.Object) throws java.lang.IllegalStateException,javax.persistence.PersistenceException,org.hibernate.exception.ConstraintViolationException: javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Duplicate entry
How can I to catch a specific exception thrown by myDAO according to the situation (in this case a constraint violation)?

You can catch the EJBException and unwrap it using exception.getCause(); to decide on further strategy.
However, I would not let the DAO throw PersistenceException into the application, wrapped or not. It will pollute your code with duplicate boilerplates with error handling on a different abstraction level.
It is advisable to handle the immediate failure inside the DAO and, if no recovery is possible, throw a business-centric application exception.
For cases, where a constraint violation is possible because you are trying to store a duplicate, consider querying for duplicates first and then modify and store the query result if appropriate. Relying on catching Exceptions instead is less readable and less efficient.

Related

Should Java JDBC Select statements always be in a Try-Catch block?

Is it good practice to put all Java JDBC Select statements in a try-catch block ? Currently I write most of my code without it. However, I do try-catch for insert/update/delete.
Note: Currently using Sprint Boot.
String sqlQuery = "Select productId, productName, productStartDate from dbo.product where productId = 5"
public getProductData() {
....
List<Product> productList = namedJdbcTemplate.query(sqlQuery, new ProductMapper());
Since this question is tagged with spring-boot and you are using JdbcTemplate, I'm giving you a Spring-specific answer.
One of the points of Spring is to avoid boilerplate from developers. If you find yourself adding things repetitively, like putting try-catch blocks around code executing DML, that's cause for suspecting you're not doing something right. Adding your own try-catches in code using Spring isn't always wrong, but it usually is.
In the Spring reference doc https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#jdbc there is a table showing what is the developer's responsibility and what is Spring's responsibility. Processing exceptions, handling the transactions, and closing jdbc resources are all shown as being Spring's responsibility.
SpringJdbc takes care of a lot of things for you. It handles closing JDBC resources and returning connections to their pool, and converts exceptions from SQLException to a hierarchy of unchecked DataAccessExceptions. In Spring unchecked exceptions thrown from a method wrapped in a transactional proxy cause the transaction to get rolled back. If you do your own try-catch logic you can prevent rollback from occurring when it needs to, if you catch the exception and the proxy never sees it. Adding try-catch logic can cause problems if you don't understand what Spring is doing.
Exceptions do need to be caught somewhere. In a Spring web application, you can set up an exception handler that catches anything thrown from the controller layer, so that you can log it. That way the action in progress gets broken off cleanly, the current transaction rolls back, and the exception gets handled in a consistent way. If you have other entry points, such as reading messages from a queue, those will need their own exception handler.
Exceptions are thrown in order to escape the current context, which isn't able to deal with the problem, and relocate control to somewhere safe. For most exceptions coming from JDBC, they aren't anything you can fix, you just want to let it be thrown, let the current transaction rollback, then let the central exception handler catch and log it.
First of all, if you're working with raw JDBC API, you should always use PreparedStatement.
Yes, you'll just have to wrap the code with try-catch block at some point, though it's a good practice to catch exceptions just right away or at the point where it's logically suits. In case of SQL queries, you actually should wrap all of them into some Service class that will give you an access to modify your database objects without running through JDBC API every time. For example:
public class UserService {
private static final String CREATE_USER_SQL = "...";
private final Connection jdbcConnection;
public #Nullable User createUser(final String name) {
try (final PreparedStatement stmt = jdbcConnection.prepareStatement(CREATE_USER_SQL)) {
jdbcConnection.setAutoCommit(false);
stmt.setString(1, name);
stmt.executeQuery();
jdbcConnection.commit();
return new User(name);
} catch (final SQLException createException) {
System.out.printf("User CREATE failed: %s\n", createException.getMessage());
try {
jdbcConnection.rollback();
} catch (final SQLException rollbackException) {
System.out.printf("Rollback failed: %s\n", rollbackException.getMessage());
}
return null;
}
}
}
This solves two problems right away:
You won't need to put boilerplate JDBC code everywhere;
It will log any JDBC errors right away, so you won't need to go through a complex debugging process.
Brief explanation:
First of all any resource involving I/O access (database access is I/O access) must always be closed or it will cause a memory leak.
Secondly, it is better to rely on try-with-resources to close any resource as having to call the .close() method manually is always exposed to the risk of not being effectively executed at runtime due to a potential Exception/RuntimeException/Error getting thrown beforehand; even closing the resource in a finally method is not preferable as such block executes at a different phase compared to the try-with-resources - auto closure of try-with-resources happens at the end of the try block, while finally executes at the end of all try/catch block - , in addition to the basic problem that it is not a secure solution as a throw might happen even inside the finally block, preventing it from completing correctly.
This said, you always need to close:
Statement/PreparedStatement/CallableStatement
any ResultSet
the whole Connection when you don't need DB access anymore
Try-catch for DB Layer code is important if you're querying with JDBC.
Think about, what if the connection broke? Or what if Database crashed ? Or some other unfortunate scenario comes up.
For these things, I will recommend you to always keep the DB layer code within try-catch.
It's also recommended for you to have some fallback mechanism in-case of the above events.
You should always handle it with try cactch.
Why: For example you started a connection to db then some exception happened, if you don't rollback your transaction it stay on db and performance will be decreased, and memory leak will be happen.
Imagine, if your connection limit is 100 and 100 exception throwed after transaction started and you didn't rollback it your system will be locked because of you can't create any new connection to your database.
But if you want an alternative for "try catch finally" you can use like this:
EmUtil.consEm(em -> {
System.out.println(em.createNativeQuery("select * from temp").getResultList().size());
});
Source code:
public final class EmUtil {
interface EmCons {
public void cons(EntityManager em);
}
public static void consEm(EmCons t) {
EntityManager em = null;
try {
em = getEmf().createEntityManager();
t.cons(em);
} finally {
if (em != null && em.getTransaction().isActive())
em.getTransaction().rollback();
if (em != null && em.isOpen())
em.close();
}
}
private static EntityManagerFactory getEmf() {
//TODO
}
}
Spring translates those exceptions as DataAccessException (for more detail link). It will be good to catch those exceptions and you can rollback with #Transactional.

#Transactional annotation doesn't work for method

I am using oracleDB and elasticsearch for persistence and if anything goes wrong in that method, it throws a custom exception. Now I need to rollback from DB if any thing fails in elastic also.
I have already added #transactional annotation on service classes. And everything I found on web.
#Transactional(rollbackOn = BaseException.class)
public void transaction(ab ab, a a) {
persistenceService.save(a);
persistenceService.updateSignalCountDb(a.abc(), a.bcd(), ab);
elasticService.saveSignal(a);
try {
elasticService.updateSignalCountElastic(a);
} catch (Exception e) {
throw new BaseException(ErrorCodes.FAILED_ELASTIC_SEARCH_UPDATE, e);
}
}
persistenceService.save() method saves in db.
persistenceService.updateSignalCountDb() method update another table in db.
elasticService.saveSignal() method saves in elastic. throws base exception in case of failure.
elasticService.updateSignalCountElastic() method update another index in elastic. It also calls elasticService.delete() method to delete anything saved in elastic in case of failure and throws a base exception.
I expected this would work in case of any failure in the entire method. But if anything fails on elastic, i get a base exception but my data from oracle db doesn't rollback.
At first glance it looks like you are doing everything right. But before you search for the reason why it doesn't work, small change in your code would prevent the problem from occurring in the first place:
#Transactional(rollbackOn = BaseException.class)
public void transaction(ab ab, a a){
try {
elasticService.saveSignal(a);
elasticService.updateSignalCountElastic(a);
persistenceService.save(a);
persistenceService.updateSignalCountDb(a.abc(), a.bcd(), ab);
}catch (Exception e){
throw new BaseException(ErrorCodes.FAILED_ELASTIC_SEARCH_UPDATE, e);
}
}
In this case your exception will occur before you even save in DB and you won't have a problem
If you are using Spring #Transactional, I researched there is only
rollbackFor option but not rollbackOn(I'm not sure this), like
this: #Transactional(rollbackFor = BaseException.class).
Make sure Transactional is enabled in spring configuration: #EnableTransactionManagement
In your case, only BaseException would trigger rollback, other Exception would not.

Validation errors handling from EJB in JSF

I would like to know what is the best way to handle validation errors in medium/big Java EE application.
Suppose I have managed bean and facade as it is below.
class SomeManagedBean {
#EJB
SomeFacade someFacade;
public void performSomeAction() {
(...)
someFacade.businessAction(loggedUser, editedEntity);
(...)
}
}
class SomeFacadeImpl {
public Object businessAction(User user, Entity entity) {
if (!isInCorrectStateToDoAction(entity)) {
// error A
}
(...)
if (!hasRightToDoAction(user, entity)) {
// error X
}
doAction(user, entity);
}
}
I expect that businessAction from SomeFacade should validate their inputs and check if it can do this business action with given arguments. It's because I may use this business method in several places in application and I do not want copy validation code.
Suppose I would like to use FacesMessage to provide to client informations about validation errors.
Some solutions:
exceptions - when something is wrong with arguments I simply throw an Exception
so I have to throw IncorrectStateForActionException, NoRightToDoActionException
why not: I can throw only one exception so I can't notify user about several things: "You don't have rights", (...), "Entity is incorrect state"
beside exception shouldn't be used to provide logic of our application
some Result class
class Result<T> {
T returnedValueFromMethod;
List<ProcessingError> errors;
}
now definition of my business method looks like:
public Result<Object> businessAction(User user, Entity entity)
when something is wrong I add error information to Result
when everything is all right I put returned value to my Result object and return this object
why not: this seems like kind of "error code" in pretty complex structure. Because of that recommendation which tells "change error codes into exception" it's understandable why we would like to avoid it.
we can do validation in facade and controller
why not: duplicated code
validation only in controller and action in facade
why not: it could be dangerous when we use this businessAction method from other place in code
we can do two methods in facade: validation and action (Query Command Separation)
result from validation should contain every possible error which may occur so it's pretty strange structure
we can do several methods for validation (errors from A to X)
it's easy to provide error messages
but this solutions seems just stupid
any other ideas?
What would be the best solution?
Do authentication/validation in business layer and let it throw an exception in case of failure. You can just handle it in JSF action method.
E.g.
#EJB
private SomeService service;
public void someAction() {
try {
service.doSomething();
addGlobalInfoFacesMessage("Doing something succeed!");
} catch (SomeBusinessException e) {
addGlobalErrorFacesMessage("Doing something failed with {0}", e.getMessage());
}
}
Or, you can let it go and have the container handle it by an <error-page> on the specific <exception-type>.
As to performing authentication and validation all by itself, the Java EE stack offers annotations like JAAS #RolesAllowed for authentication and JSR303 #NotNull, #Size, etc for model. This should reduce the if check boilerplate inside the service methods itself.

Is there a way to translate HibernateException to something else, then DataAccessException in Spring

I am trying to make more sense out of constraint violation errors, happening during transaction persistence in Hibernate.
The only way I see how to interfere with HibernateExceptions is through PersistenceExceptionTranslator in spring,
package org.springframework.dao.support;
import org.springframework.dao.DataAccessException;
public interface PersistenceExceptionTranslator {
DataAccessException translateExceptionIfPossible(RuntimeException ex);
}
which translates Hibernate exceptions to DataAccessExceptions, but that means I'll need to inherit my exception hierarchy from DataAccessExceptions.
Is there any other natural way to do this, without introducing DataAceessExceptions in Exception inheritance hierarchy?
You can catch HibernateException and rethrow it as a checked exception from your repository method. But then you will have to deal with the exception in the upper layers, but you also can simply keep throwing it outside your code layer.

How to catch OptimisticLockException in servlet level?

I'm using JPA toplink-essential, building REST web app.
I have a servlet that find one entity and delete it.
Below code I thought I could catch optimistic lock exception in servlet level but its not!
Instead RollbackException is thrown, and that's what documentation says:
But then when I see the Netbean IDE GlassFish log, somewhere, optimisticLockException is thrown. It's just not being caught in my code. (my system print message doesn't get displayed so I'm sure its not going in there.)
I tried to import each packages (one at a time of course) and tested with catch clause but both time, it is not going into the catch block even though log error says "optimistic exception".
import javax.persistence.OptimisticLockException;
import oracle.toplink.essentials.exceptions.OptimisticLockException;
So where the OptimisticLockException is thrown?????
#Path("delete")
#DELETE
#Consumes("application/json")
public Object planDelete(String content) {
try {
EntityManager em = EmProvider.getInstance().getEntityManagerFactory().createEntityManager();
EntityTransaction txn = em.getTransaction();
txn.begin();
jObj = new JSONObject(content);
MyBeany bean = em.find(123);
bean.setVersion(Integer.parseInt(12345));
em.remove(bean);
//here commit!!!!!
em.getTransaction().commit();
}
catch(OptimisticLockException e) { //this is not caught here :(
System.out.pritnln("here");
//EntityTransactionManager.rollback(txn);
return HttpStatusHandler.sendConflict();
}
catch(RollbackException e) {
return HttpStatusHandler.sendConflict();
}
catch(Exception e) {
return HttpStatusHandler.sendServerError(e);
}
finally {
if(em != null) {
em.close();
}
}
Error msg:
[TopLink Warning]: 2011.01.28 05:11:24.007--UnitOfWork(22566987)
--Exception [TOPLINK-5006]
(Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))):
oracle.toplink.essentials.exceptions.OptimisticLockException
[TopLink Warning]: 2011.02.01 08:50:15.095--UnitOfWork(681660)--
javax.persistence.OptimisticLockException: Exception [TOPLINK-5006] (Oracle TopLink
Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))):
oracle.toplink.essentials.exceptions.OptimisticLockException
Not 100% sure, but could it be that you're catching javax.persistence.OptimisticLockException (notice the package), but as the thrown exception is oracle.toplink.essentials.exceptions.OptimisticLockException, it's not getting caught? Even though the name of exception-class is the same, they're not the same class.
I would guess that it is thrown in the em.getTransaction().commit(); statement.
Because the java doc of RollbackException if said:
Thrown by the persistence provider when EntityTransaction.commit() fails.
I strongly belive that this is not the code you realy use (it would not compile because of a missing ) in line bean.setVersion(Integer.parseInt(12345);), but i "hope" that the real code has the same problem.
Have you tried calling entityManager.flush(); inside your try/catch block? When JPA flushes is when the OptimisticLock exception is thrown.
Also you need not commit the transaction in the manner you did. You simply could have done txn.commit(); instead of em.getTransaction().commit();.
I have a similar situation where I am able to catch javax.persistence.OptimisticLockException. In my case I made the ReST endpoint a SSB and inject the entity manager. I then call a method on another SSB which is also injected and acts as a controller for this piece of biz logic. This controller performs a flush() and catches the OLEX and rethrows and ApplicationException which the Rest endpoint / SSB catches and retries. Using this pattern you also need to make sure to specify TransactionAttributeType.RequiresNew so that each retry you make occurs in a fresh transaction since the OLEX invalidates the old one.

Categories

Resources