How to use Oracle XMLType in Hibernate

  • Edit your Hibernate Mapping XML

<?xml version=”1.0″?>
<!DOCTYPE hibernate-mapping PUBLIC
“-//Hibernate/Hibernate Mapping DTD 3.0//EN”
“http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd” >

<hibernate-mapping>

<class
name=”mypackage.MyClass”
table=”MYTABLE”
>

<id
name=”myId”
type=”java.lang.Long”
column=”MY_ID”
>

<generator class=”sequence”>
<param name=”sequence”>my_id_seq</param>
</generator>

</id>

<property
name=”myXml”
type=”mypackage.HibernateXMLType”
column=”MY_XML”
/>

</class>

</hibernate-mapping>

  • Edit your Java Persistence Object

public class MyClass implements Serializable {

private Document myXml;

public Document getMyXml() {
return myXml;
}

public void setMyXml(Document messageXml) {
this.myXml = messageXml;
}
}

  • Add required JARS
    You would need xdb.jar, xmlparserv2.jar, and ojdbc14.jar

  • Create HibernateXMLType class

package mypackage;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import oracle.jdbc.OracleResultSet;
import oracle.sql.OPAQUE;
import oracle.xdb.XMLType;

import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class HibernateXMLType implements UserType, Serializable {
// all other methods are ommitted at present for brevity

private static final long serialVersionUID = 2308230823023l;
private static final Class returnedClass = Document.class;
private static final int[] SQL_TYPES = new int[] { oracle.xdb.XMLType._SQL_TYPECODE };

public int[] sqlTypes() {
return SQL_TYPES;
}

public Class returnedClass() {
return returnedClass;
}

public int hashCode(Object _obj) {
return _obj.hashCode();
}

public Object assemble(Serializable _cached, Object _owner)
throws HibernateException
{
try {
return HibernateXMLType.stringToDom((String)_cached);
}
catch (Exception e) {
throw new HibernateException(“Could not assemble String to Document”, e);
}
}

public Serializable disassemble(Object _obj)
throws HibernateException
{
try {
return HibernateXMLType.domToString((Document)_obj);
}
catch (Exception e) {
throw new HibernateException(“Could not disassemble Document to Serializable”, e);
}
}

public Object replace(Object _orig, Object _tar, Object _owner) {
return deepCopy(_orig);
}

public boolean equals(Object arg0, Object arg1)
throws HibernateException
{
if(arg0 == null && arg1 == null) return true;
else if (arg0 == null && arg1 != null ) return false;
else return arg0.equals(arg1);
}

public Object nullSafeGet( ResultSet rs, String [ ] names, Object arg2 )
throws HibernateException, SQLException
{
XMLType xmlType = null;
Document doc = null;
try {
OPAQUE op = null;
OracleResultSet ors = null;
if (rs instanceof OracleResultSet) {
ors = (OracleResultSet)rs;
} else {
throw new UnsupportedOperationException(“ResultSet needs to be of type OracleResultSet”);
}
op = ors.getOPAQUE(names[0]);
if(op != null) {
xmlType = XMLType.createXML ( op );
}
doc = xmlType.getDOM();
}finally {
if (null != xmlType) {
xmlType.close();
}
}
return doc;
}

public void nullSafeSet( PreparedStatement st, Object value, int index )
throws HibernateException, SQLException
{
try {
XMLType xmlType = null;
if (value != null) {
xmlType = XMLType.createXML(st.getConnection(),HibernateXMLType.domToString((Document)value));
}
st.setObject(index, xmlType);
}
catch (Exception e) {
throw new SQLException(“Could not convert Document to String for storage”);
}
}

public Object deepCopy(Object value)
throws HibernateException
{
if (value == null) return null;

return (Document)((Document)value).cloneNode(true);
}

public boolean isMutable() {
return false;
}

protected static String domToString(Document _document)
throws TransformerException
{
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, “yes”);
DOMSource source = new DOMSource(_document);
StringWriter sw=new StringWriter();
StreamResult result = new StreamResult(sw);
transformer.transform(source, result);
return sw.toString();
}

protected static Document stringToDom(String xmlSource)
throws SAXException, ParserConfigurationException, IOException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(xmlSource.getBytes(“UTF-8″)));
}
}

Note that in your Hibernate Mapping XML you would declare the type as HibernateXMLType, but your getter and setter in your Java Persistence Object would be of type Document.

Note also that this won’t work if you are also using JSF as the UI layer and deploying it on GlassFish/Sun App Server (i.e. Hibernate + Oracle XML Type + JSF + Sun App Server = disaster). Refer to http://forums.java.net/jive/thread.jspa?messageID=224967

Does your application have a JAXP parser bundled? There is some behavior change in how the JAXP parser is picked up since b43. Before b43, the system default JAXP parser is always picked up (which is the one came with JDK1.5) to parse the deployment descriptors. After b43, if there is
a parser packaged in the user application, that parser will be given higher priority which is the expected behavior specified in here

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>