Home » Eclipse Projects » EclipseLink » How to get Eclipselink to fire JSR303 constraints in mapped super class?(303 constraints on mapped super classes...)
| | | | |
Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1749275 is a reply to message #1733253] |
Mon, 05 December 2016 07:03 |
Nuno Godinho de Matos Messages: 34 Registered: September 2012 |
Member |
|
|
Hi,
I believe that this issue is of fundamental importance and it still manifests in eclipselink version 2.6.4.
If you see the stack overflow issue under:
http://stackoverflow.com/questions/37310853/how-to-get-eclipselink-to-fire-jsr303-constraints-in-mapped-super-class/40942442#40942442
You can see that there is a bug in the implementation of BeanValidationHelper.
The work around for this issue is having all beans that have relevant JSR bean validation rules in a parent super class to be annotated with a dummy field:
@Transient
@NotNull
private final char waitForEclipseLinkToFixTheVersion264 = 'a';
While some of the JSR constraints will be implemented on the DB itself, that will ensure that fields that cannot be null are effectively not null, other business logic validation rules that you would normally not have implemented in the DB will not get evaluated.
Non trivial constraints such as @AssertTrue will not be stop blocked in the DB.
In my opinion the 2.6.4 release of eclipselink needs an urgent patch fix release to address this issue.
If I am not mistaken, eclipselink.jar 2.6.4 is being bundled in products like weblogic 12.2.1.2, so it would really be good to get a fix into the 2.6.x release for this.
In fact, the issue seems to be even more serious.
I have spotted another unit test test where JSR validations on tracked entities are not being triggered on the Flush() and on the commit().
In this case eclipse link is behaving as if a managed entity did not have any tracked changes done on it,.
The scenario is something of the form:
Unit Test being Transtation()
em.persit(entityA)
unit test do some irrelevant changes.
unitTestModifityEntityA in a way where beanValidation will blow up.
em.fluish()
Nothing happens with eclipse link.
em.Commit() also nothing happens changes get committed.
It looks as if once you do em.persist() on the entity and chage it during the course of an ongoing transaction, eclipse link is not tracking the changes.
During unit tests, our entities are not statically weaved.
This is a very serious bug in 2.6.4. Very very serious.
Fortunately the eclipselink code in 2.6.4 version seems much better documented.
I will see if I can figure out while entity A is not being listed a a candidate for validation during the flush and commit.
I am very worried with this bug.
A 100% show stopper.
These unit tests outside the container do not use static weaving.
You are supposed to be able to make the unit test pass both in withing eclipse IDE as well as maven. Weaving of entities is only being done during deployment in the container.
For the time being JSR 303 on eclipselink 2.6.4 looks like it is far from working properly.
Many thanks.
[Updated on: Mon, 05 December 2016 08:32] Report message to a moderator
|
|
|
Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1749303 is a reply to message #1749275] |
Mon, 05 December 2016 09:32 |
Nuno Godinho de Matos Messages: 34 Registered: September 2012 |
Member |
|
|
Ok,
I believe the second bug is now identified.
The first bug is already described in the stack overflow issue and in this post, and it has to do with the BeanValidatorListener not detecting properly when the "shouldValidate" flag needs to be true.
To work-around this bug the current solutation is to hack into the child entity a a @Transiennt field that has a @NotNull to force the flag to come true.
The second bug, which corresponds to the last description of my post, has to do with the fact that the
BeanValidationListner class itself only treats as relevant events the"
prePersist and the preUpdate and pre remove.
This is of course not sufficient.
If you persist an entity at the early beggining of a transaction, you modify it during the transaction and then later change a field on the entity making it invalid.
The pre-persist is not called, because the enity is already in the unit of work.
The preUpdate does nothing, because the server session cache does not have any enityt there.
So when the flush is doin
Quote:g:
public ObjectChangeSet calculateChanges(Object clone, Object backUp, boolean isNew, UnitOfWorkChangeSet changeSet, UnitOfWorkImpl unitOfWork, ClassDescriptor descriptor, boolean shouldRaiseEvent) {
// PERF: Avoid events if no listeners.
if (descriptor.getEventManager().hasAnyEventListeners() && shouldRaiseEvent) {
// The query is built for compatibility to old event mechanism.
WriteObjectQuery writeQuery = new WriteObjectQuery(clone.getClass());
writeQuery.setObject(clone);
writeQuery.setBackupClone(backUp);
writeQuery.setSession(unitOfWork);
writeQuery.setDescriptor(descriptor);
descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreWriteEvent, writeQuery));
if (isNew) {
descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreInsertEvent, writeQuery));
} else {
descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreUpdateEvent, writeQuery));
}
}
The two envents that get called are:
---------> descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreWriteEvent, writeQuery));
and
---------> descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreInsertEvent, writeQuery));
FDor the BeanValidationListner, the public void the preWrite event is empty:
preWrite(DescriptorEvent event) {} is
See the base class"
public class DescriptorEventAdapter implements DescriptorEventListener {
That implements every method with empty body.
Likewise, the preInser boty is empty.
So the following call:
Quote:descriptor.getEventManager().executeEvent(new DescriptorEvent(DescriptorEventManager.PreInsertEvent, writeQuery));
It will also not trigger the change event set.
Notice, bellow I post the relevant stack trace on a flush call that is 100% ineffective because of the current implementation of the BeanValidationListener.class
DescriptorEventManager.notifyEJB30Listeners(DescriptorEvent) line: 691
DescriptorEventManager.executeEvent(DescriptorEvent) line: 229
DeferredChangeDetectionPolicy.calculateChanges(Object, Object, boolean, UnitOfWorkChangeSet, UnitOfWorkImpl, ClassDescriptor, boolean) line: 82
DeferredChangeDetectionPolicy.calculateChangesForNewObject(Object, UnitOfWorkChangeSet, UnitOfWorkImpl, ClassDescriptor, boolean) line: 48
RepeatableWriteUnitOfWork(UnitOfWorkImpl).calculateChanges(Map, UnitOfWorkChangeSet, boolean, boolean) line: 662
RepeatableWriteUnitOfWork.writeChanges() line: 441
EntityManagerImpl.flush() line: 874
OUT_INTEGRATION_TEST.FLUSHING_AN_ENTITY_AND_SHOUD_GET_AN_ERROR_BUT_DOES_NOT() line: 614
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 498
FrameworkMethod$1.runReflectiveCall() line: 50
FrameworkMethod$1(ReflectiveCallable).run() line: 12
FrameworkMethod.invokeExplosively(Object, Object...) line: 47
InvokeMethod.evaluate() line: 17
RunBefores.evaluate() line: 26
RunAfters.evaluate() line: 27
BlockJUnit4ClassRunner(ParentRunner<T>).runLeaf(Statement, Description, RunNotifier) line: 325
BlockJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 78
|
|
| |
Goto Forum:
Current Time: Fri Apr 26 15:12:57 GMT 2024
Powered by FUDForum. Page generated in 0.03812 seconds
|