Dear all,
When I apply validation like @Size to a collection that is lazy loaded, I get the following error:
Code:
AssertionFailure, - 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 [...] was not processed by flush()
at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:205)
at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:333)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:28)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:456)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:709)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:678)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
at
...
I have searched and found a similar, unresolved, issue in Hibernate JIRA:
http://opensource.atlassian.com/project ... owse/HV-37However, my problem is with collection of entities, not composite-element as in HV-37.
I have look in to the Hibernate Validator code and found that in ClassValidator, member of a class is validated if it is already initialized. This check is done using Hibernate.isPropertyInitialized(). The following is the code copied from ClassValidator.InvalidValue[] getInvalidValues(T bean, Set<Object> circularityState)
Code:
for ( int i = 0; i < memberValidators.size() ; i++ ) {
XMember getter = memberGetters.get( i );
if ( Hibernate.isPropertyInitialized( bean, getPropertyName( getter ) ) ) {
Object value = getMemberValue( bean, getter );
Validator validator = memberValidators.get( i );
if ( !validator.isValid( value ) ) {
String propertyName = getPropertyName( getter );
results.add( new InvalidValue( interpolate(validator), beanClass, propertyName, value, bean ) );
}
}
}
In my case Hibernate.isPropertyInitialized always return true, since my entity is not proxied, but its collection member is. The Hibernate code for isPropertyInitialzied is as follow (decompiled using Jad):
Code:
public static boolean isPropertyInitialized(Object proxy, String propertyName)
{
Object entity;
if(proxy instanceof HibernateProxy)
{
LazyInitializer li = ((HibernateProxy)proxy).getHibernateLazyInitializer();
if(li.isUninitialized())
return false;
entity = li.getImplementation();
} else
{
entity = proxy;
}
if(FieldInterceptionHelper.isInstrumented(entity))
{
FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor(entity);
return interceptor == null || interceptor.isInitialized(propertyName);
} else
{
return true;
}
}
For my entity, calling this method for any of it member will fall to the last else case returning true.
So, I try changing the Hibernate Validator code into:
Code:
for ( int i = 0; i < memberValidators.size() ; i++ ) {
XMember getter = memberGetters.get( i );
if ( Hibernate.isPropertyInitialized( bean, getPropertyName( getter ) ) ) {
Object value = getMemberValue( bean, getter );
if ( value == null || Hibernate.isInitialized( value ) ) {
Validator validator = memberValidators.get( i );
if ( !validator.isValid( value ) ) {
String propertyName = getPropertyName( getter );
results.add( new InvalidValue( interpolate(validator), beanClass, propertyName, value, bean ) );
}
} else {
log.info("Unintialized value not validated: "+getPropertyName( getter ));
}
}
}
and the problem seems to be disappeared. The nearby code that validate child entity also perform some check like this. Since I'm new to Hibernate and Hibernate Validator, I am not sure if my modification will really work and why this check is not performed in the first place. So, could you guys please give me some suggestions?
I'm using:
Hibernate 3.2.6 GA,
Hibernate Annotation 3.3.1 GA,
Hibernate EntityManager 3.3.2 GA,
Hibernate Validator 3.0.0 GA
Thank you in advance,
Pongtawat