我最近使用自定义的hibernate UserType映射了一个类的字段。
这是我的自定义用户类型
package service.dao.hibernate;
import java.io.IOException;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.SimpleType;
import com.google.common.base.Objects;
public abstract class JSONUserType implements UserType { //ParameterizedType, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final ObjectMapper Mapper;
private static final String CLASS_TYPE = "classType";
private static final String TYPE = "type";
private static final int[] SQL_TYPES = new int[] { Types.LONGVARCHAR,
Types.CLOB, Types.BLOB };
private Class classType;
private int sqlType = Types.LONGVARCHAR; // before any guessing
static {
Mapper = new ObjectMapper();
Mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
@Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return this.deepCopy(cached);
}
@Override
public Object deepCopy(Object value) throws HibernateException {
Object copy = null;
if (value != null) {
try {
return Mapper.readValue(Mapper.writeValueAsString(value),
this.classType);
} catch (IOException e) {
throw new HibernateException("unable to deep copy object", e);
}
}
return copy;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
try {
return Mapper.writeValueAsString(value);
} catch (JsonProcessingException e) {
throw new HibernateException("unable to disassemble object", e);
}
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
} else if (x == null || y == null) {
return false;
} else {
return x.equals(y);
}
}
@Override
public int hashCode(Object x) throws HibernateException {
return null == x ? 0 : x.hashCode();
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Object obj = null;
if (!rs.wasNull()) {
if (this.sqlType == Types.CLOB || this.sqlType == Types.BLOB) {
byte[] bytes = rs.getBytes(names[0]);
if (bytes != null) {
try {
obj = Mapper.readValue(bytes, createJavaType(Mapper));
} catch (IOException e) {
throw new HibernateException(
"unable to read object from result set", e);
}
}
} else {
try {
String content = rs.getString(names[0]);
if (content != null) {
obj = Mapper.readValue(content, createJavaType(Mapper));
}
} catch (IOException e) {
throw new HibernateException(
"unable to read object from result set", e);
}
}
}
return obj;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, this.sqlType);
} else {
if (this.sqlType == Types.CLOB || this.sqlType == Types.BLOB) {
try {
st.setBytes(index, Mapper.writeValueAsBytes(value));
} catch (JsonProcessingException e) {
throw new HibernateException(
"unable to set object to result set", e);
}
} else {
try {
st.setString(index, Mapper.writeValueAsString(value));
} catch (JsonProcessingException e) {
throw new HibernateException(
"unable to set object to result set", e);
}
}
}
}
@Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return this.deepCopy(original);
}
// @Override
// public Class returnedClass() {
// return this.classType;
// }
@Override
public int[] sqlTypes() {
return SQL_TYPES;
}
// @Override
// public void setParameterValues(Properties params) {
// String classTypeName = params.getProperty(CLASS_TYPE);
// try {
// this.classType = ReflectHelper.classForName(classTypeName,
// this.getClass());
// } catch (ClassNotFoundException cnfe) {
// throw new HibernateException("classType not found", cnfe);
// }
// String type = params.getProperty(TYPE);
// if (type != null) {
// this.sqlType = Integer.decode(type).intValue();
// }
// }
/**
* By default we are expecting to use a simple object / not a collection (Set, List)
*
* @param mapper : instance jackson object mapper
*
* @return A jackson JavaType to specify wich object represent the json string representation
*
*/
public JavaType createJavaType (ObjectMapper mapper){
return SimpleType.construct(returnedClass());
}
}
这是特定的用户类型
package model.common;
import service.dao.hibernate.JSONUserType;
public class DocumentInfoType extends JSONUserType {
@Override
public Class returnedClass() {
return DocumentInfo.class;
}
}
这是我的自定义类型字段的实体
package model.common;
import model.SimpleAuditedEntity;
import model.lk.DocumentMode;
import model.lk.DocumentType;
import service.dao.hibernate.JSONUserType;
import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import java.sql.Timestamp;
/**
* The persistent class for the documents database table.
*
*/
@Entity
@Table(name = "documents")
@NamedQuery(name = "Document.findAll", query = "SELECT d FROM Document d")
public class Document extends SimpleAuditedEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "content_type")
private String contentType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "type")
private DocumentType documentType;
@Column
private Timestamp created;
@Column
private String description;
@Column
private String filename;
@Column
private String name;
@Column
private String ref;
@Type(type = "model.common.DocumentInfoType")
@Column
private DocumentInfo info;
public Document() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getContentType() {
return this.contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public Timestamp getCreated() {
return this.created;
}
public void setCreated(Timestamp created) {
this.created = created;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getFilename() {
return this.filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getRef() {
return this.ref;
}
public void setRef(String ref) {
this.ref = ref;
}
/**
* @return the documentType
*/
public DocumentType getDocumentType() {
return documentType;
}
/**
* @param documentType
* the documentType to set
*/
public void setDocumentType(DocumentType documentType) {
this.documentType = documentType;
}
public DocumentMode getDocumentMode() {
return this.documentType != null ? DocumentMode
.getType(this.documentType.getId()) : DocumentMode.UNDEFINED;
}
/**
* @return the info
*/
public DocumentInfo getInfo() {
return info;
}
/**
* @param info the info to set
*/
public void setInfo(DocumentInfo info) {
this.info = info;
}
}
问题是当我启动应用程序时,我立即得到异常
Caused by: org.hibernate.MappingException: property mapping has wrong number of columns: model.common.Document.info type: model.common.DocumentInfoType
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:497) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.mapping.RootClass.validate(RootClass.java:270) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.cfg.Configuration.validate(Configuration.java:1360) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:852) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
有什么想法吗?我已经映射了所有列,但我尝试了很多修改但没有任何修改!
提前致谢
答案 0 :(得分:3)
从JSONUserType.sqlTypes()返回包含3个元素的SQLTypes数组:
private static final int[] SQL_TYPES = new int[] { Types.LONGVARCHAR,
Types.CLOB, Types.BLOB };
这告诉hibernate你的类型映射到3列。 您应该只选择其中一种类型。
请参阅UserType.sqlTypes()的javadoc:
返回此类型映射的列的SQL类型代码