需求
需要从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");
}
}
}