Mapping Oracle XMLType to Document with Hibernate

在使用C3P0数据库连接池时,以下示例代码可实现oracle.xdb.XMLType与org.w3c.dom.Document之间的转化。经过测试,在weblogic、tomcat服务器均能正常运行。

问题描述:

在weblogic服务器上热部署Web应用新版本后,频繁出现错误(Caused by: java.lang.NoClassDefFoundError: oracle/xml/parser/v2/XMLSAXSerializer)

解决办法:

  • 检查热部署的Web应用新版本web.war包(或所依赖的lib.war包)中是否包含xdb-11.0.0.7.jar,xmlparserv2-11.2.0.1.jar,若有则将其从包中删除,替换自定义类型OracleXmlType.java为本文最后面附上的代码,关键方法是
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object arg2) throws HibernateException, SQLException {
        XMLType xmlType = null;
        Document doc = null;
        try {
            OPAQUE op = null;
            if (rs instanceof OracleResultSet) {
                OracleResultSet ors = null;
                ors = (OracleResultSet) rs;
                op = ors.getOPAQUE(names[0]);
            } else if (rs instanceof NewProxyResultSet) {
                Object obj = rs.getObject(names[0]);
                if(obj instanceof OPAQUE){
                    op = (OPAQUE) obj;
                }
            } else {
                throw new UnsupportedOperationException("ResultSet needs to be of type OracleResultSet");
            }
            if (op != null) {
                xmlType = XMLType.createXML(op);
                doc = xmlType.getDocument();
            }
        } finally {
            if (null != xmlType) {
                xmlType.close();
            }
        }
        return doc;
    }
  • 修改~/.bash_profile,在CLASSPATH中加上/home/weblogic/xdb-11.0.0.7.jar:/home/weblogic/xmlparserv2-11.2.0.1.jar;执行source ~/.bash_profile以使CLASSPATH设置生效。

  • 登录weblogic控制台,在“环境>服务器”,选择一个服务器实例,然后在“配置>服务器启动”,把类路径留为空,保存好配置;在“环境>部署”,删掉应用到服务器实例上的所有web、lib包。

  • 重启NodeManager:
    1.找到NodeManager的进程ID(ps -ef|grep NodeManager)
    2.kill掉NodeManager的进程(kill -9 进程ID)
    3.启动NodeManager(cd /home/weblogic/Oracle/Middleware/wlserver_10.3/server/bin/ && nohup ./startNodeManager.sh &)

  • 重启服务器实例,变为Running状态后,先后部署步骤1更新后的lib.war、web.war包。

完整的OracleXmlType.java代码:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.sql.Connection;
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 org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.mchange.v2.c3p0.impl.NewProxyResultSet;

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

public class OracleXmlType implements UserType, Serializable {

    private static final long serialVersionUID = 1L;
    @SuppressWarnings("rawtypes")
    private static final Class RETURNDCLASS = Document.class;
    private static final int[] SQL_TYPES = { oracle.xdb.XMLType._SQL_TYPECODE };

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

    @SuppressWarnings("rawtypes")
    @Override
    public Class returnedClass() {
        return RETURNDCLASS;
    }

    @Override
    public int hashCode(Object obj) {
        return obj.hashCode();
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        try {
            return OracleXmlType.stringToDom((String) cached);
        } catch (Exception e) {
            throw new HibernateException("Could not assemble String to Document", e);
        }
    }

    @Override
    public Serializable disassemble(Object obj) throws HibernateException {
        try {
            return OracleXmlType.domToString((Document) obj);
        } catch (Exception e) {
            throw new HibernateException("Could not disassemble Document to Serializable", e);
        }
    }

    @Override
    public Object replace(Object orig, Object tar, Object owner) {
        return deepCopy(orig);
    }

    @Override
    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 {
            try {
                return OracleXmlType.domToString((Document) arg0).equals(OracleXmlType.domToString((Document) arg1));
            } catch (TransformerException e) {
                return false;
            }
        }
    }

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

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
        OracleNativeExtractor extrator = new OracleNativeExtractor();
        Connection nativeConn = extrator.getNativeConnection(st.getConnection());

        try {
            XMLType xmlType = null;
            if (value != null) {
                xmlType = new oracle.xdb.XMLType(nativeConn, OracleXmlType.domToString((Document) value));
            }
            st.setObject(index, xmlType);
        } catch (Exception e) {
            throw new SQLException("Could not covert Document to String for storage");
        }
    }

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

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

    @Override
    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")));
    }

}

(原文发表于:http://www.wangdandong.com/2015/08/24/mapping-oracle-xmltype-to-document-with-hibernate.html )

你可能感兴趣的:(Mapping Oracle XMLType to Document with Hibernate)