How to handle exceptions raised by #Transactional annotation. In a case where TransactionSystemException includes a ConstraintViolationException due to not null constraint violation for an entity annotated with #Entity.
I am using Hibernate.
This particular exception should be handled by fixing the bug it reveals: the code is trying to create an object with a null property, and this property may not be null. It means that the code forgot to populate this property, or didn't handle the validation of the user-entered data correctly.
I have left thinking about "having a need of exception finally!" here is another way to test and validate the constraints and constraint violations. Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set> constraintViolations = validator.validateValue(Course.class, "name", null); assertEquals(1, constraintViolations.size()); –
Related
this is my sample application with it's test. I've defined some constraints on repository as #NotEmpty. When I want to call this repository I'm getting following issue
javax.validation.ConstraintDeclarationException: HV000141: The constraint org.hibernate.validator.constraints.NotEmpty used ConstraintTarget#IMPLICIT where the target cannot be inferred.
Do I need to implement validator for #NotEmpty or is this a bug in hibernate or my spring-boot application?
note when I remove #NotEmpty from return type, it works.
You are running into an interesting corner case here, where for a purely composed constraint it cannot be determined whether it applies to the parameters or the return value of a method. Back in the time of Bean Validation 1.1 we decided to leave it to implementations to handle this case as it's very rare.
Hibernate Validator allows to resolve this case by specifying #SupportedValidationTarget(ValidationTarget.ANNOTATED_ELEMENT) on the constraint definition. This was added in HV 5.2, but then it seems we forgot to make use of it for #NotEmpty and potentially other purely composed constraints defined by HV. Could you therefore please file a bug report in our JIRA instance?
Note that you shouldn't have the problem with the #NotEmpty defined in Bean Validation 2.0 (HV 6.0), as this isn't declared as a purely composed constraint.
Update: this issue has been fixed in Hibernate Validator 6.0.3.Final (and backported to 5.3.6.Final and 5.4.2.Final).
I have entities with validation annotations such as #NotNull. I don't know how to prevent a container managed transaction from rolling back in the case of a ConstraintViolationException in a bulk persist operation such as:
public void persistAll(List<TheEntity> entities) throws Exception{
for(TheEntity ent : entities){
em.persist(ent);
}
}
Wrapping the persist operation in a try-catch would not solve the issue because even by catching the Constraint exception, the transaction would be flagged for rollback (none of the other "validated" entities would be persisted). I could isolate the transaction per entity to persist, but I think this will impact a lot on performance (not sure about this, I'm using eclipselink with batch JDBC optimization).
I know that the behavior of the ContraintValidationException is working as the JPA spec mandates (flagging rollback), but I'm not sure if I'm understanding how the eclipselink batch optimization works (does the bulk opeations need to be in a single transaction?).
Thanks for the interest.
Regards.
EDIT: Welp, eclipelink docs state that "Batch writing can improve database performance by sending groups of INSERT, UPDATE, and DELETE statements to the database in a single transaction, rather than individually.", so yes, it needs to be done in a single transaction.
EDIT: I could also inject a constraint validator from the context and disable the JPA validator on persistence.xml, so I can validate the entity list prior the JPA PrePersist operation. However, this will affect other entities that won't need bulk operations on them but still need validation. Ahh! almost there.
You can do manual validation and just skip the entities that are not valid, like this:
// in the class inject validator
#Resource
Validator validator;
...
for(TheEntity ent : entities){
if( validator.validate(ent).size() == 0) {
// valid - persist
em.persist(ent);
} else {
// invalid - skip
}
}
Does an equivalent for the Hibernate filters exist in the JPA?
The following hibernate annotation can be for example used in order to define a filter:
#Entity
#FilterDef(name="minLength", parameters=#ParamDef( name="minLength", type="integer" ) )
#Filters( {
#Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
#Filter(name="minLength", condition=":minLength <= length")
} )
public class Forest { ... }
I would like to use something equivalent from JPA in order to restrict read access to some entities. How it can be done using clean JPA, without Hibernate annotations?
I didn't find any serious and reliable solution.
I analysed the "JPA Security" project. However, its home page was last updated two years ago, its last version is 0.4.0 and it doesn't seem to be a reliable solution. It's not a standard and it is not popular.
Other alternative in Hibernate which can be used in my case to restrict read access to an entity is the Hibernate Interceptor API - the following interface method can be implemented in order to append a SQL string which contains some additional conditions:
org.hibernate.Interceptor.onPrepareStatement(String sql)
or the following method can be overriden:
org.hibernate.EmptyInterceptor.onPrepareStatement(String sql)
I found out that there are some JPA event callbacks and annotations, e.g. #PostLoad. However, none of these can be used in my case, because I need something to restrict access to entities based on some conditions (user role).
Anyone knows how it can be done using JPA standards?
It seems to me that you are attempting to perform validations on entity objects. You have a few options to accomplish this.
The first would be to use the Java Validations API and its associated validations. This is the recommended approach with Java EE, of which JPA is a part. For example, you could write your entity class as follows:
#Entity
class Person {
#NotNull
#Size(min = 5, Max = 50)
String name;
}
Now, every time you attempt to persist an instance of Person, the JPA provider will automatically validate the instance, provided there is a Java Validator on the classpath. Validation errors will be thrown as runtime exceptions and can be used to rollback transactions. It is also possible to invoke a validator manually, collect any validation errors and transform them into user-friendly messages if required.
The other (probably dirty) option is to use the JPA Event Listeners, perform validations and throw an exception if a validation fails. This will terminate the JPA operation immediately and rollback any transactions.
Is it possible to stop hibernate from auto updating a persistent object?
#Transactional
public ResultTO updateRecord(RequestTO requestTO) {
Entity entity = dao.getEntityById(requestTO.getId());
// now update the entity based on the data in the requestTO
ValidationResult validationResult = runValidation(entity);
if(validationResult.hasErrors()) {
// return ResultTO with validation errors
} else {
dao.persist(entity);
}
}
Here is what happens in the code, I retrieve the entity which would be considered by hibernate to be in persistent state, then I update some of the fields in the entity, then pass the entity to validation. if validation fails, then don't udpate, if validation succeeds then persist the entity.
Here is the main issue with this flow: because I updated the entity for it to be used in the validation, it does not matter whether I call persist() method (on the DAO) or not, the record will always be updated because hibernate detects that the entity has been changed and flags it for update.
Keep im mind I can change the way i do validation and work around the issue, so I'm not interested in workarounds. I'm interested in knowing how i would be able to disable the hibernate feature where it automatically updates persistent objects.
Please keep in mind I'm using hibernates' implementation of JPA. so Hibernate specific answers dealing with hibernate specific API will not work for me.
I tried to look for hibernate configuration and see if I can set any configuration to stop this behavior but no luck.
Thanks
--EDIT ---
I couldn't find a solution to this, so I opted to rolling back the transaction without throwing any RuntimeException even though I'm in a declarative transaction using:
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
which works like a charm.
Configure FlushMode for your session.
http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/FlushMode.html
You can use EntityManager.clear() method after getting object from database.
http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#clear()
You can call the following code:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
Throw an exception if validation fails and have the caller handle that.
Consider the following entity class, used with, for example, EclipseLink 2.0.2 - where the link attribute is not the primary key, but unique nontheless.
#Entity
public class Profile {
#Id
private Long id;
#Column(unique = true)
private String link;
// Some more attributes and getter and setter methods
}
When I insert records with a duplicate value for the link attribute, EclipseLink does not throw a EntityExistsException, but throws a DatabaseException, with the message explaining that the unique constraint was violated.
This doesn't seem very usefull, as there would not be a simple, database independent, way to catch this exception. What would be the advised way to deal with this?
A few things that I have considered are:
Checking the error code on the DatabaseException - I fear that this error code, though, is the native error code for the database;
Checking the existence of a Profile with the specific value for link beforehand - this obviously would result in an enormous amount of superfluous queries.
When I insert records with a duplicate value for the link attribute, EclipseLink does not throw a EntityExistsException
Yes, and a JPA provider is not supposed to throw an EntityExistException in that case, you won't get an EntityExistException on something else than the primary key.
(...) but throws a DatabaseException, with the message explaining that the unique constraint was violated.
This is very WRONG from EclipseLink, a JPA provider should throw a PersistenceException or a subclass but certainly not a specific exception like o.e.p.e.DatabaseException. This is a bug and should be reported as such as I already mentioned in a previous answer.
This doesn't seem very usefull, as there would not be a simple, database independent, way to catch this exception. What would be the advised way to deal with this?
Same answer as above, see my previous answer.
It's too bad they don't have a ConstraintViolationException in JPA. I've created a helper method to determine if the PersistenceException is a constraint violation for a given class - it is hibernate only though. I imagine there is a way to do it using other implementations.
protected Boolean isUniqueConstraintViolation(PersistenceException ex, Class entity) {
if (((NonUniqueObjectException)ex.getCause()).getEntityName().equals(entity.getName())) {
return true;
}
return false;
}