How to marshal Hibernate proxies Intended Audience Prerequisite Concept
Intended Audience
Anyone who want’s to marshal Hibernate POJOs. This document shows
how prevent undesirable XML output caused by Hibernate's lazy-loading
technique.
Prerequisite
A general understanding about the Hibernate persistence framework, its use
of dynamic proxies for lazy-loading and Castor XML.
Concept
Assume that we have a Hibernate POJO named Person, which stores
basic information about persons and set of Address objects. Address
itself is another Hibernate POJO. This set of address objects is mapped in the
Hibernate mapping file to load lazily, as shown below in the Hibernate mapping for
the Person object:
<hibernate-mapping>
<class name="xxx.yyy.Person" table="person">
<id name="id" type="integer">
<column name="id" length="10" />
<generator class="native" />
</id>
<!-- Properties section -->
<property name="firstName" type="string">
<column name="first_name" length="80" not-null="true" />
</property>
<property name="lastName" type="string">
<column name="last_name" length="128" not-null="true" />
</property>
<set name="Address" table="address" inverse="true"
cascade="all-delete-orphan" lazy="true">
<key column="person_id" />
<one-to-many class="xxx.yyy.Address" />
</set>
</class>
</hibernate-mapping> |
|
When we want to marshal a Person object to XML, we use a standard
Castor XML mapping file to map the Person class to the desired XML
layout.
<mapping>
<class name="xxx.yyy.Person">
<map-to xml="person"/>
<field name="firstName" type="string" >
<bind-xml name="firstName" node="element" />
</field>
<field name="lastName" type="string">
<bind-xml name="lastName" node="element" />
</field>
<field name="address" type="xxx.yyy.Address" collection="set">
<bind-xml name="address" node="element" location="addressList" />
</field>
</class>
</mapping> |
|
As shown below, marshalling the Person instance produces undesirable
XML output. This is because hibernate (or other ORM frameworks) use dynamic proxy
classes for lazy-loading.
<person>
<firstName>John</firstName>
<lastName>Smith</lastName>
<addressList>
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="java:xxx.yyy.Address_$$_javassist_11">
<hibernate-lazy-initializer unwrap="false" uninitialized="false"
xsi:type="java:org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer">
<implementation xsi:type="address">
<street>street</street>
<country>England</country>
</implementation>
<entity-name>xxx.yyy.Address</entity-name>
</hibernate-lazy-initializer>
<street>street</street>
<country>England</country>
</address>
</addressList>
</person>
|
|
As Hibernate returns dynamic proxies for lazy-loaded objects, Castor won't be able to
find a mapping for these (proxy) classes, and in this case fall back to using
introspection. To avoid this behaviour, Castor XML during marshalling must be (en)able(d)
to detect such proxy classes and handle them in a special way.
As proxy objects usually implement proxy interfaces, Castor XML can be instructed
to check for such interfaces at marshal time, and marshal classes that implement
these interfaces in a different way. Castor XML, in its castor.properties
configuration file, allows you to enlist (proxy) interfaces that should be used for
checking. The property org.exolab.castor.xml.proxyInterfaces
can be used to specify whether or not to search for interfaces. If the property is
set, the objects to be marshalled will be analysed if they implement one of the
given interface names. If that's the case, the superclass will be marshalled
instead of the proxy class itself.
org.exolab.castor.xml.proxyInterfaces = net.sf.cglib.proxy.Factory, org.hibernate.proxy.HibernateProxy
|
|
Setting this property as hown above now enables Castor XML to produce
the desired output.
<person>
<firstName>John</firstName>
<lastName>Smith</lastName>
<addressList>
<address>
<street>street</street>
<country>Engand</country>
</address>
</addressList>
</person> |
|
|