Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » How to get Eclipselink to fire JSR303 constraints in mapped super class?(303 constraints on mapped super classes...)
icon4.gif  How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1732842] Fri, 20 May 2016 17:20 Go to next message
Fred Welland is currently offline Fred WellandFriend
Messages: 3
Registered: May 2016
Junior Member
EclipsLink doesnt' seem to detect or fire JSR303 annotation constraints in a base class that is the mapped super class of an entity during a persist() operation.

For example:
public Base
{
    @NotNull
    private Integer id; 

    private String recordName; 

    //other stuff (getters etc) 
}


and then:

public class MyObject
    extends Base
{
     //stuff...
}


and then:

<mapped-superclass class="Base">
    <attributes>
         <basic name="recordName">
             <column name = "NAME" />
         </basic>
    </attributes>
</mapped-superclass> 


and finally:

<entity class="MyObject">
    <table name="TheTable"/>
        <attributes>
            <id name="id">
                <column name="recordId" />
            </id>
        </attributes>
</entity>     


Some other relevant parameters:

* using jpa 2.1 -- specifically eclipslink 2.6.2 and 2.6.3
* I am integration testing - so java se (and spock)
* JDK 1.8.77
* I do have hibernate validator in my classpath (org.hibernate:hibernate validator:5.2.4.Final)
* If I write a test fixture and use validitor.validate() directly (no jpa or persist) hibernate validator works as expected.
* I do NOT use JPA annotations and only use ORM xml to declare entity mappings.
* I do use JSR303 annotations to mark attrs and props with constraints.

persistence.xml is marked with validation "AUTO" and many variations of properties like javax.persistence.validation.group.pre-persist with FQDN of marker interfaces have been tried.

As mentioned, calling em.persist(myObjectInst) will not fire any 303 annotations added to class 'Base'.

Is there some tuning parameter or switch I can tinker with that will make this work?

Note: I did a deep-dive debug on this and can see that org.eclipse.persistence.internal.jpa.metadata.beanvalidation.BeanValidationHelper.detectConstraints() does NOT look at any parent classes for JSR303 annotations. It seems to only want to look at the specific entity class. I'd hazard to guess that if I moved my JSR303 constraints to the concrete (or entity class); it may just work. But then I would loose the extension and mapped super class stuff. So what fun is that?
Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1732958 is a reply to message #1732842] Mon, 23 May 2016 12:40 Go to previous messageGo to next message
Lukas JungmannFriend
Messages: 33
Registered: November 2013
Location: Prague, Czech Republic
Member
are you able to reproduce the issue with 2.6.4?

thanks,
--lukas
Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1732959 is a reply to message #1732842] Mon, 23 May 2016 12:47 Go to previous messageGo to next message
Fred Welland is currently offline Fred WellandFriend
Messages: 3
Registered: May 2016
Junior Member
I have not tried.

Nor can I find it (2.6.4) in a maven/gradle repo -- well the ones I use routinely...Maybe it is in a snapshot or nightly repo somewhere?

Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1732961 is a reply to message #1732959] Mon, 23 May 2016 13:00 Go to previous messageGo to next message
Lukas JungmannFriend
Messages: 33
Registered: November 2013
Location: Prague, Czech Republic
Member
ah, my bad, not sure why my mind changed 2.6.3 (which you've said you use) to 2.6.4 Sad I'm sorry for confusion.

Anyway can you try it with the latest 2.7.0 snapshot? See https://wiki.eclipse.org/EclipseLink/Maven for details how to get it...

thanks
Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1733253 is a reply to message #1732961] Wed, 25 May 2016 10:45 Go to previous messageGo to next message
Fred Welland is currently offline Fred WellandFriend
Messages: 3
Registered: May 2016
Junior Member
Razz

Got back to this.

So flipping between:

    //compile 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.6.3'
    compile 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.0-SNAPSHOT'


will make the @NotNull in class Base work (while in 2.7.0) and not work (when in 2.6.3)


I am going to try some more tests; but looks like the 2.7.0 release may have addressed this issue. TX!!!!


(so when does it go GA?)
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 Go to previous messageGo to next message
Nuno Godinho de Matos is currently offline Nuno Godinho de MatosFriend
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 Go to previous messageGo to next message
Nuno Godinho de Matos is currently offline Nuno Godinho de MatosFriend
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
Re: How to get Eclipselink to fire JSR303 constraints in mapped super class? [message #1749316 is a reply to message #1749303] Mon, 05 December 2016 11:56 Go to previous message
Nuno Godinho de Matos is currently offline Nuno Godinho de MatosFriend
Messages: 34
Registered: September 2012
Member
There is now a repository that allows both bugs to be verified.

https://github.com/99sono/EclipseLink_2_6_4_JSR_303Bug


Git clone,
Mvn clean install.

Two tests fail demonstrating the two bugs.

Two placebo tests demonstrating either work-around or the base use case.


In the last commit to the repository there is a throw-away work around that will sufice for the time being, util eclipselink patches the 2.6.x branch.
The work around is based on getting an event listener to call the BeanValidationListner from eclipselink, to have the pre-insert event being alidated as well.


Please have a look.

[Updated on: Mon, 05 December 2016 15:39]

Report message to a moderator

Previous Topic:dynamic upates
Next Topic:right way to maintain bi-directional relationships
Goto Forum:
  


Current Time: Mon Apr 06 10:09:22 GMT 2020

Powered by FUDForum. Page generated in 0.02280 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top