[hibernate-issues] [Hibernate-JIRA] Commented: (HV-246) BeanValidationEventListener has a bug (technically a problem with hibernate-annotations 3.5.0beta1... but I couldn't find that project)
Emmanuel Bernard (JIRA)
noreply at atlassian.com
Wed Oct 14 13:02:41 EDT 2009
[ http://opensource.atlassian.com/projects/hibernate/browse/HV-246?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=34198#action_34198 ]
Emmanuel Bernard commented on HV-246:
-------------------------------------
I don't know what you mean by stateless connection but for sure if you create a new stateful (ie normal) session atop your current JDBC connection, it works (you need to load the objects with your new session and not reuse the existing objects).
I don't know how you can do that with Spring though.
> BeanValidationEventListener has a bug (technically a problem with hibernate-annotations 3.5.0beta1... but I couldn't find that project)
> ---------------------------------------------------------------------------------------------------------------------------------------
>
> Key: HV-246
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HV-246
> Project: Hibernate Validator
> Issue Type: Bug
> Affects Versions: 4.0.0.CR1
> Environment: hibernate 3.3.2ga, hibernate validator 4.0cr1, hibernate-annotations 3.5.0beta1
> Reporter: Ken Egervari
> Priority: Blocker
> Fix For: 4.1.0
>
>
> The interaction with a hibernate session and sessions created within a validator do not work together.
> For example, here is a test case:
> {code}
> @Test
> public void jobSeekersCanSaveAPreviousResumeWithTheSameName() {
> JobSeekerResume resume = ( JobSeekerResume ) resumeDao.find( 1 );
> resume.setDescription( "new desc." );
> resumeDao.save( resume );
> flush();
> jdbcMap = simpleJdbcTemplate.queryForMap(
> "select * from resume where resume_id = ?", resume.getId() );
> assertEquals( resume.getDescription(), jdbcMap.get( "DESCRIPTION" ) );
> }
> {code}
> the flush() method creates an exception:
> {code}
> ERROR AssertionFailure:45 - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
> org.hibernate.AssertionFailure: collection [jawbs.domain.jobseeker.JobSeeker.categories] was not processed by flush()
> at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228)
> at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:356)
> at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
> at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
> at jawbs.DatabaseTests.flush(DatabaseTests.java:113)
> {code}
> Obviously hibernate core is saying this could be a bug, or it could be unsafe.
> Now, the reason this happens is because JobSeekerResume has a contraint that accesses the hibernate session. Now, I have many, many constraints that use this constraint and they work fine. This is the only test that is causing problems for me, and I don't have a clue why.
> Nonetheless, I'm going to give you a lot of code. Here is the constraint annotation on JobSeekerResume:
> {code}
> @QueryConstraint(
> hql = "select count(*) from JobSeekerResume where name = :name and id != :id and jobSeeker.id = :jobSeeker.id",
> message = "{jobSeekerResume.name.unique}",
> enabled = true
> )
> {code}
> And here is the code for the validator implementation:
> {code}
> public class QueryConstraintValidator extends ValidatorSupport<QueryConstraint,DomainObject> {
> /* Fields */
> private String hql;
> private boolean enabled;
> /* Services */
> public void initialize( QueryConstraint queryConstraint ) {
> this.hql = queryConstraint.hql();
> this.enabled = queryConstraint.enabled();
> }
> public boolean isValid( DomainObject domainObject ) {
> return isValid( domainObject, null );
> }
> @Override
> protected boolean preValidate() {
> return !enabled;
> }
> protected boolean testQuery( Session session, DomainObject domainObject ) {
> logger.debug( "Enabled - Validating constraint with: " );
> logger.debug( hql );
> Query query = session.createQuery(
> HqlParser.removePeriodsFromParameterNames( hql )
> );
> BeanWrapper beanWrapper = new BeanWrapperImpl( domainObject );
> for( String parameterName : HqlParser.getParameterNames( hql ) ) {
> query.setParameter(
> HqlParser.removePeriodsFromParameterName( parameterName ),
> beanWrapper.getPropertyValue( parameterName )
> );
> }
> boolean result = (Long) query.uniqueResult() == 0;
> logger.debug( "isValid is returning: " + result );
> return result;
> }
> ...
> }
> {code}
> The support constraint (the important one most likely) is as follows:
> {code}
> public abstract class ValidatorSupport<T extends Annotation,U> implements ConstraintValidator<T,U> {
> /* Fields */
> protected static Logger logger =
> LoggerFactory.getLogger( QueryConstraintValidator.class );
> /* Services */
> public boolean isValid( U object, ConstraintValidatorContext constraintValidatorContext ) {
> if( preValidate() ) {
> return true;
> }
> SessionFactory sessionFactory =
> ( SessionFactory ) ApplicationContextProvider.getBean(
> "sessionFactory" );
> if( sessionFactory != null ) {
> Session session = sessionFactory.openSession();
> Transaction tx = session.beginTransaction();
> boolean result = testQuery( session, object );
> tx.commit();
> session.close();
> return result;
> }
> return true;
> }
> protected boolean preValidate() {
> return false;
> }
> protected abstract boolean testQuery( Session session, U object );
> }
> {code}
> Lastly, here is the mapping of the JobSeeker subclass:
> {code}
> <subclass name="jawbs.domain.jobseeker.JobSeeker" discriminator-value="ROLE_JOBSEEKER">
> <property name="isPrivate" column="is_private" />
> <bag name="categories" table="job_seeker_to_category" cascade="all-delete-orphan" inverse="true">
> <key column="job_seeker_id"/>
> <many-to-many class="jawbs.domain.Category" column="category_id"/>
> </bag>
> <bag name="watchedJobs" table="job_seeker_to_watched_job" cascade="all-delete-orphan" inverse="true">
> <key column="job_seeker_id"/>
> <many-to-many class="jawbs.domain.job.Job" column="watched_job_id"/>
> </bag>
> <bag name="applications" table="candidate" cascade="all-delete-orphan" inverse="true">
> <key column="job_seeker_id"/>
> <many-to-many class="jawbs.domain.candidate.Candidate" column="candidate_id"/>
> </bag>
> <bag name="blacklistedEmployers" table="job_seeker_to_blacklisted_employer">
> <key column="job_seeker_id"/>
> <many-to-many class="jawbs.domain.employer.Employer" column="blacklisted_employer_id"/>
> </bag>
> <bag name="resumes" table="resume" inverse="true" cascade="all-delete-orphan">
> <key column="job_seeker_id"/>
> <one-to-many class="jawbs.domain.resume.Resume" />
> </bag>
> </subclass>
> {code}
> And here is the mapping of the subclass of resume:
> {code}
> <subclass name="jawbs.domain.resume.JobSeekerResume" discriminator-value="JOBSEEKER">
> <many-to-one name="jobSeeker" class="jawbs.domain.jobseeker.JobSeeker"
> column="job_seeker_id" />
> </subclass>
> {code}
> If you need any more assistance, please let me know. This is a critical blocker to getting a test to pass, this is most likely 100% fine.
> Thanks
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
More information about the hibernate-issues
mailing list