I think there is a small problem in the new hibernate bean manager.... holdPersistentObject method in the Hibernate bean manager checks the property assaignability against Collection and map (with isAssignableForm)
and then if this case(isCollection variable) is false, it checks another instanceOf against collection and map
in the body of if condition.
if ((ClassUtils.immutable(propertyClass) == false) &&
(ClassUtils.isJavaPackage(propertyClass) == false) &&
(isCollection == false)) ------> I think this is a problem...
{
Thanks
Erkin
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Did you have a look at release 1.1.1 ?
Here is the holdPersistentObject method :
"protected boolean holdPersistentObject(Object pojo)
{
try
{
// Precondition checking
//
if (pojo == null)
{
return false;
}
if (_persistenceUtil.isPersistentPojo(pojo) == true)
{
return true;
}
// Iterate over properties
//
BeanInfo info = Introspector.getBeanInfo(pojo.getClass());
PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
for (int index = 0; index < descriptors.length; index++)
{
PropertyDescriptor descriptor = descriptors[index];
Class<?> propertyClass = descriptor.getPropertyType();
if ((ClassUtils.immutable(propertyClass) == false) &&
(ClassUtils.isJavaPackage(propertyClass) == false))
{
// Not a basic type, so a check is needed
//
// Get property value
Method readMethod = descriptor.getReadMethod();
readMethod.setAccessible(true);
Object propertyValue = readMethod.invoke(pojo, (Object[])null);
if (propertyValue == null)
{
continue;
}
// Get real property class
propertyClass = propertyValue.getClass();
The current release code is in branch '1.1'.
The trunk contains the code of the upcoming release (1.2), which has been fully refactored (I rewrote the whole proxy informations handling, and added some new features).
Regards
Bruno
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It is really good info for me as I will not continue trying to build trunk.... Unfortunately (unfortunate because I don't want to disturb you.) I have one more question.
When I try to send one of my domain object to client side, I'm getting security exception because of java assist proxy implementation. (host mode is working fine, but problem occurs on app server)
But I got actually another error before that while hibernateBeanManager is cloning the object.
PropertyDescriptor for javassist.util.proxy.MethodHandler in the generated class does not have any getter method for Method handler. So
"Method readMethod = descriptor.getReadMethod();" call in the holdPersistentObject method returns nulls and I'm getting null pointer exception.
I put a simple hack as a work around but it didnt solve my security exception problem.
Caused by: com.google.gwt.user.client.rpc.SerializationException: Type 'My_Domian_Object_$$_javassist_3' was not included in the set of types whic
h can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.
Thanks your help...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Finally, I think I found a workaround for my problem. Let me explain you
what happened.
I'm trying build a system which is using gwt 1.5.2, hibernate
3.2.6.ga, Spring 2.5.5, hibernate4gwt1.1.1, gwt-sl 0.1.5a basically
latest version of everything. (As project is not live yet, I would
like to keep up with the release)
The problem(it might be known but i wasnt aware) was getting an
object ,which is enabled for lazy loading, from server side to client
side.
E.x
class Service{
Set<Contract> contracts;
}
class Contract{
Service service;
// Basic types and their getter setter
}
as you can see, there is a bidirectional relationship between Service
and Contract. So hibernate-mapping settings in the Service.hbm.xml is
like below
The business scenario is getting all of contracts for a specific
serviceId.
Implementation at the server side was exactly what it is shown at http://www.hibernate.org/328.html
so My generic DAO had following method.
@SuppressWarnings("unchecked")
public T findById(ID id, boolean lock) {
T entity;
if (lock)
entity = (T) getSession().load(getPersistentClass(), id,
LockMode.UPGRADE);
else
entity = (T) getSession().load(getPersistentClass(), id);
return entity;
}
and My business method was
Service getContracts(int serviceId){
Service service = this.findById(serviceId, false);
if (service != null) {
Set<Contrat> contracts= service.getContracts();
contracts.size(); //Note: this is a temporary solution to
prevent JRE code optimization before going to production.
}
return service;
}
At this point getContracts method returned Service_javasisst as it is
in the pre email..... And hibernate4gwt was not able to clone this
object before serialization for RPC by throwing the exception in the
previous email.
In order to fix the problem, I changed load calls in the findById with
get calls.
@SuppressWarnings("unchecked")
public T findById(ID id, boolean lock) {
T entity;
if (lock)
entity = (T) getSession().get(getPersistentClass(), id,
LockMode.UPGRADE);
else
entity = (T) getSession().get(getPersistentClass(), id);
return entity;
}
So Only thing I need to be aware is not to expect HibernateException
for unknown ids instead I need to do null checking on the returning
obj.
Thanks
Erkin
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I just forgot to add the cause of this difference. If you look at the code in the
org.hibernate.event.LoadEventListener.java, you will see the difference between GET LoadType and LOAD LoadType
public static final LoadType GET = new LoadType("GET")
.setAllowNulls(true)
.setAllowProxyCreation(false) --> important
.setCheckDeleted(true)
.setNakedEntityReturned(false);
public static final LoadType LOAD = new LoadType("LOAD")
.setAllowNulls(false)
.setAllowProxyCreation(true) --> important
.setCheckDeleted(true)
.setNakedEntityReturned(false);
Thanks
Erkin
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I really think that Hibernate "session.load" is pretty useless, except on very specific case, because it creates a uninitialized proxy that will lead to lazy loading on first access.
Nevertheless, I consider the exception thrown on proxy as a bug and will try to fix it ASAP.
Regards
Bruno
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Bruno
I think there is a small problem in the new hibernate bean manager.... holdPersistentObject method in the Hibernate bean manager checks the property assaignability against Collection and map (with isAssignableForm)
and then if this case(isCollection variable) is false, it checks another instanceOf against collection and map
in the body of if condition.
if ((ClassUtils.immutable(propertyClass) == false) &&
(ClassUtils.isJavaPackage(propertyClass) == false) &&
(isCollection == false)) ------> I think this is a problem...
{
Thanks
Erkin
Hi Erkin,
Did you have a look at release 1.1.1 ?
Here is the holdPersistentObject method :
"protected boolean holdPersistentObject(Object pojo)
{
try
{
// Precondition checking
//
if (pojo == null)
{
return false;
}
if (_persistenceUtil.isPersistentPojo(pojo) == true)
{
return true;
}
// Iterate over properties
//
BeanInfo info = Introspector.getBeanInfo(pojo.getClass());
PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
for (int index = 0; index < descriptors.length; index++)
{
PropertyDescriptor descriptor = descriptors[index];
Class<?> propertyClass = descriptor.getPropertyType();
if ((ClassUtils.immutable(propertyClass) == false) &&
(ClassUtils.isJavaPackage(propertyClass) == false))
{
// Not a basic type, so a check is needed
//
// Get property value
Method readMethod = descriptor.getReadMethod();
readMethod.setAccessible(true);
Object propertyValue = readMethod.invoke(pojo, (Object[])null);
if (propertyValue == null)
{
continue;
}
// Get real property class
propertyClass = propertyValue.getClass();
if ((_classMapper != null) &&
(_classMapper.getSourceClass(propertyClass) != null))
{
propertyClass = _classMapper.getSourceClass(propertyClass);
}
if (_persistenceUtil.isPersistentClass(propertyClass) == true)
{
return true;
}
// collection and recursive search handling
if (propertyValue != null)
{
if (propertyValue instanceof Collection<?>)
{
// Check collection values
//
Collection<?> propertyCollection = (Collection<?>)propertyValue;
for(Object value : propertyCollection)
{
if (holdPersistentObject(value) == true)
{
return true;
}
}
}
else if (propertyValue instanceof Map<?, ?>)
{
// Check map entry and values
//
Map<?,?> propertyMap = (Map<?, ?>) propertyValue;
for(Map.Entry<?, ?> value : propertyMap.entrySet())
{
if ((holdPersistentObject(value.getKey()) == true) ||
(holdPersistentObject(value.getValue()) == true))
{
return true;
}
}
}
else
{
// Recursive search
//
if (holdPersistentObject(propertyValue) == true)
{
return true;
}
}
}
}
}
// No persistent property
return false;
}
catch (Exception e)
{
throw new InvocationException(e);
}
}"
Does it look ok to you ?
Regards
Bruno
Hey Bruno
Thanks for your help again... One more question, Is latest version of the code always in trunk?
Thanks
Again
Hi,
The current release code is in branch '1.1'.
The trunk contains the code of the upcoming release (1.2), which has been fully refactored (I rewrote the whole proxy informations handling, and added some new features).
Regards
Bruno
Hi Bruno
It is really good info for me as I will not continue trying to build trunk.... Unfortunately (unfortunate because I don't want to disturb you.) I have one more question.
When I try to send one of my domain object to client side, I'm getting security exception because of java assist proxy implementation. (host mode is working fine, but problem occurs on app server)
But I got actually another error before that while hibernateBeanManager is cloning the object.
PropertyDescriptor for javassist.util.proxy.MethodHandler in the generated class does not have any getter method for Method handler. So
"Method readMethod = descriptor.getReadMethod();" call in the holdPersistentObject method returns nulls and I'm getting null pointer exception.
I put a simple hack as a work around but it didnt solve my security exception problem.
Caused by: com.google.gwt.user.client.rpc.SerializationException: Type 'My_Domian_Object_$$_javassist_3' was not included in the set of types whic
h can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.
Thanks your help...
Hi Bruno
Finally, I think I found a workaround for my problem. Let me explain you
what happened.
I'm trying build a system which is using gwt 1.5.2, hibernate
3.2.6.ga, Spring 2.5.5, hibernate4gwt1.1.1, gwt-sl 0.1.5a basically
latest version of everything. (As project is not live yet, I would
like to keep up with the release)
The problem(it might be known but i wasnt aware) was getting an
object ,which is enabled for lazy loading, from server side to client
side.
E.x
class Service{
Set<Contract> contracts;
}
class Contract{
Service service;
// Basic types and their getter setter
}
as you can see, there is a bidirectional relationship between Service
and Contract. So hibernate-mapping settings in the Service.hbm.xml is
like below
<set name="contracts" inverse="true" lazy="true" cascade="all">
<key column="serviceId" not-null="true" />
<one-to-many class="myDomain.Contract"/>
</set>
The business scenario is getting all of contracts for a specific
serviceId.
Implementation at the server side was exactly what it is shown at
http://www.hibernate.org/328.html
so My generic DAO had following method.
@SuppressWarnings("unchecked")
public T findById(ID id, boolean lock) {
T entity;
if (lock)
entity = (T) getSession().load(getPersistentClass(), id,
LockMode.UPGRADE);
else
entity = (T) getSession().load(getPersistentClass(), id);
return entity;
}
and My business method was
Service getContracts(int serviceId){
Service service = this.findById(serviceId, false);
if (service != null) {
Set<Contrat> contracts= service.getContracts();
contracts.size(); //Note: this is a temporary solution to
prevent JRE code optimization before going to production.
}
return service;
}
At this point getContracts method returned Service_javasisst as it is
in the pre email..... And hibernate4gwt was not able to clone this
object before serialization for RPC by throwing the exception in the
previous email.
In order to fix the problem, I changed load calls in the findById with
get calls.
@SuppressWarnings("unchecked")
public T findById(ID id, boolean lock) {
T entity;
if (lock)
entity = (T) getSession().get(getPersistentClass(), id,
LockMode.UPGRADE);
else
entity = (T) getSession().get(getPersistentClass(), id);
return entity;
}
So Only thing I need to be aware is not to expect HibernateException
for unknown ids instead I need to do null checking on the returning
obj.
Thanks
Erkin
Last Note:
I just forgot to add the cause of this difference. If you look at the code in the
org.hibernate.event.LoadEventListener.java, you will see the difference between GET LoadType and LOAD LoadType
public static final LoadType GET = new LoadType("GET")
.setAllowNulls(true)
.setAllowProxyCreation(false) --> important
.setCheckDeleted(true)
.setNakedEntityReturned(false);
public static final LoadType LOAD = new LoadType("LOAD")
.setAllowNulls(false)
.setAllowProxyCreation(true) --> important
.setCheckDeleted(true)
.setNakedEntityReturned(false);
Thanks
Erkin
Hi Erkin,
I really think that Hibernate "session.load" is pretty useless, except on very specific case, because it creates a uninitialized proxy that will lead to lazy loading on first access.
Nevertheless, I consider the exception thrown on proxy as a bug and will try to fix it ASAP.
Regards
Bruno
Hi Bruno
Thanks for your consideration... I'm ready to help as well.
Erkin