基於不同版本Hibernate的OracleXmlType處理
阿新 • • 發佈:2018-12-11
需求
需要從Oracle資料庫中查出xmltype型別的資料,並且與pojo類中的org.w3c.dom.Document型別的欄位對應。由於Hibernate4(4.3.11.Final)和Hibernate5(5.3.7.Final)對於org.hibernate.usertype.UserType介面的nullSafeGet和nullSafeSet方法的形參定義不同,所以在Hibernate4和Hibernate5下對應Oracle的xmltype資料的OracleXmlType類的定義也不同。
Hibernate4專案
DatDocument.java
package com.jake.hib4.pojo; import lombok.Data; import org.hibernate.annotations.Type; import org.w3c.dom.Document; import javax.persistence.*; @Data @Entity @Table(name = "DAT_DOCUMENT") public class DatDocument { @Id @Column(name = "APP_ID", unique = true, nullable = false, length = 100) private String datDocumentId; @Type(type = "com.jake.hib4.hiextype.OracleXmlType") @Column(name = "DOCUMENT_DATA", columnDefinition = "XMLTYPE") private Document document; }
在Hibernate4的專案中對於OracleXmlType的定義如下:
OracleXmlType.java
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.jake.hib4.hiextype; 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.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.xdb.XMLType; import org.apache.commons.lang3.StringUtils; import org.hibernate.HibernateException; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.usertype.UserType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; public class OracleXmlType implements UserType, Serializable { private static final long serialVersionUID = 2308230823023L; private static final Class returnedClass = Document.class; private static final int[] SQL_TYPES = new int[]{2007}; private static final Logger LOG = LoggerFactory.getLogger(OracleXmlType.class); public OracleXmlType() { } 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 stringToDom((String)_cached); } catch (Exception var4) { throw new HibernateException("Could not assemble String to Document", var4); } } public Serializable disassemble(Object _obj) throws HibernateException { try { return domToString((Document)_obj); } catch (Exception var3) { throw new HibernateException("Could not disassemble Document to Serializable", var3); } } public Object replace(Object _orig, Object _tar, Object _owner) { return this.deepCopy(_orig); } public boolean equals(Object arg0, Object arg1) throws HibernateException { if (arg0 == null && arg1 == null) { return true; } else { return arg0 == null && arg1 != null ? false : arg0.equals(arg1); } } public Object deepCopy(Object value) throws HibernateException { return value == null ? null : (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("indent", "yes"); if (_document == null) { return "<root></root>"; } else { 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(); if (StringUtils.isBlank(xmlSource)) { xmlSource = "<root></root>"; } return builder.parse(new ByteArrayInputStream(xmlSource.getBytes("UTF-8"))); } public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor arg2, Object arg3) throws HibernateException, SQLException { XMLType xmlType = null; try { xmlType = (XMLType)rs.getObject(names[0]); } catch (Exception var7) { LOG.error("Hibernate get XMLType Data Error!", var7); } return xmlType != null ? xmlType.getDOM() : null; } public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor arg3) throws HibernateException, SQLException { OracleNativeExtractor extrator = new OracleNativeExtractor(); Connection nativeConn = extrator.getNativeConnection(st.getConnection()); try { XMLType xmlType = null; if (value != null) { xmlType = new XMLType(nativeConn, domToString((Document)value)); } st.setObject(index, xmlType); } catch (Exception var8) { throw new SQLException("Could not covert Document to String for storage"); } } }
Hibernate5專案
DatDocument.java
package com.jake.hib5.pojo; import lombok.Data; import org.hibernate.annotations.Type; import org.w3c.dom.Document; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Data @Entity @Table(name = "DAT_DOCUMENT") public class DatDocument { @Id @Column(name = "APP_ID", unique = true, nullable = false, length = 100) private String datDocumentId; @Type(type = "com.jake.hib5.type.OracleXmlType") @Column(name = "DOCUMENT_DATA", columnDefinition = "XMLTYPE") private Document document; }
OracleXmlType.java
package com.jake.hib5.type;
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.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import com.gzsolartech.smartforms.hiextype.OracleNativeExtractor;
import oracle.xdb.XMLType;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* 此類被DatDocument的document欄位的@Type註解引用
* 原本@Type引用com.jake.hib4.hiextype.OracleXmlType,但該類實現的UserType介面來自Hibernate4,
* 其nullSafeGet和nullSafeSet方法的第三個引數與Hibernate5不同:Hibernate4為SessionImplementor,
* Hibernate5為SharedSessionContractImplementor,Postman訪問時會報AbstractMethodError:nullSafeGet/nullSafeSet。
* 所以,解決方法就是重寫OracleXmlType類,實現Hibernate5的UserType介面。
*/
public class OracleXmlType implements UserType, Serializable {
private static final long serialVersionUID = 2308230823023L;
private static final Class returnedClass = Document.class;
private static final int[] SQL_TYPES = new int[]{2007};
private static final Logger LOG = LoggerFactory.getLogger(OracleXmlType.class);
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 stringToDom((String)_cached);
} catch (Exception var4) {
throw new HibernateException("Could not assemble String to Document", var4);
}
}
public Serializable disassemble(Object _obj) throws HibernateException {
try {
return domToString((Document)_obj);
} catch (Exception var3) {
throw new HibernateException("Could not disassemble Document to Serializable", var3);
}
}
public Object replace(Object _orig, Object _tar, Object _owner) {
return this.deepCopy(_orig);
}
public boolean equals(Object arg0, Object arg1) throws HibernateException {
if (arg0 == null && arg1 == null) {
return true;
} else {
return arg0 == null && arg1 != null ? false : arg0.equals(arg1);
}
}
public Object deepCopy(Object value) throws HibernateException {
return value == null ? null : (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("indent", "yes");
if (_document == null) {
return "<root></root>";
} else {
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();
if (StringUtils.isBlank(xmlSource)) {
xmlSource = "<root></root>";
}
return builder.parse(new ByteArrayInputStream(xmlSource.getBytes("UTF-8")));
}
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor arg2, Object arg3) throws HibernateException, SQLException {
XMLType xmlType = null;
try {
xmlType = (XMLType)rs.getObject(names[0]);
} catch (Exception var7) {
LOG.error("Hibernate get XMLType Data Error!", var7);
}
return xmlType != null ? xmlType.getDOM() : null;
}
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor arg3) throws HibernateException, SQLException {
OracleNativeExtractor extractor = new OracleNativeExtractor();
Connection nativeConn = extractor.getNativeConnection(st.getConnection());
try {
XMLType xmlType = null;
if (value != null) {
xmlType = new XMLType(nativeConn, domToString((Document)value));
}
st.setObject(index, xmlType);
} catch (Exception var8) {
throw new SQLException("Could not covert Document to String for storage");
}
}
}