Consider a simple entity _Node_ with two properties: * name (*required* with a @NotNull and the db column is *not* allowing nulls) * label (*optional* and the db column is allowing nulls)
Then consider this test:
{code:java} @Test public void test1() { accept(em -> { Node n = new Node(); em.persist(n); n.setName("node-1"); n.setLabel("label-1"); }); } {code}
test1 will fail with:
{noformat} Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'NAME' cannot accept a NULL value. {noformat}
The *incoherence* is in the fact that no consistent behavior is met. A consistent behavior is either one: * a javax.validation.ConstraintViolationException (for @NotNull) should be thrown (on persist or flush/commit) * or test1 should pass
Supposing that the expected behavior is a validation exception being thrown, the validator is executed on the entity on flush/commit time, but at that time the entity has the "name" set. Then, this leads to an out-of-sync between the entity being validated and the generated statement to be executed, making validation return a false positive.
To show it, consider a second simple test:
{code:java} @Test public void test2() { accept(em -> { Node n = new Node(); em.persist(n); }); } {code}
Correctly, this is failing with: {noformat} Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [hibernate.model.Node] during persist time for groups [javax.validation.groups.Default, ] List of constraint violations:[ ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=name, rootBeanClass=class hibernate.model.Node, messageTemplate='{javax.validation.constraints.NotNull.message}'} ] {noformat}
On the other hand, supposing that the expected behavior is that test1 should pass, the incoherence is due to statement generation time.
To show it, consider a second simple test: {code:java} @Test public void test3() { accept(em -> { Node n = new Node(); n.setName("node-3");
em.persist(n); n.setLabel("label-3"); }); Node n = apply(em -> em.createQuery("select x from Node x", Node.class).getSingleResult()); Assert.assertEquals("label-3", n.getLabel()); } {code}
Even if the test passes, *two* statements are generated (and executed).
{noformat} Hibernate: insert into Node (label, name, id) values (?, ?, ?) Hibernate: update Node set label=?, name=? where id=? {noformat}
I suppose the first statement is generated on persist and the second on flush/commit; but, in this case, I'm expecting a single insert statement generated on flush/commit time and *immediately after* the entity has been validated (then on flush/commit time) .
In conclusion, I see to two possible solutions: * run the validator inside persist() * postpone statements generation to flush/commit time
I will upload a test case as soon as I can. Thank you.
|
|