我试图通过使用“带有Hibernate v5.1.0的PostgreSQL的JSONB数据类型”实现一个Maven项目,并使用一个名为“ MyJsonType”的自定义用户类型作为“ jsonb”数据类型。因此,我没有得到与“ MyJsonType”相关的其他配置信息。我尝试了以下文章。
但是使用JPA处理了相同的概念(使用EntityManager来持久化对象)但是这里使用了HIBERNATE API
请检查最后一个代码块中的完整错误日志。
我还没有实现MyJsonType.java,MyPostgreSQL94Dialect.java,package-info.java,这些已经定义好了,并按照下面的文章从git中获取。
我使用下面的链接来完成此示例项目:
https://www.thoughts-on-java.org/persist-postgresqls-jsonb-data-type-hibernate/
感谢您的帮助。
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-5.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.url">jdbc:postgresql://localhost:5433/sample_database</property>
<property name="hibernate.connection.username">postgres</property>
<property name="hibernate.connection.password">admin</property>
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">true</property>
<property name="hibernate.dialect">com.code.model.MyPostgreSQL94Dialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping class="com.code.model.Address" />
</session-factory>
</hibernate-configuration>
地址.java
package com.code.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
@Entity
@Table(name = "address")
public class Address implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="emp_id", updatable = false, nullable = false)
private Long empId;
@Column(name="emp_Details")
@Type(type = "MyJsonType")
private MyJson empDetails;
public long getEmpId() {
return empId;
}
public void setEmpId(long empId) {
this.empId = empId;
}
public MyJson getEmpDetails() {
return empDetails;
}
public void setEmpDetails(MyJson empDetails) {
this.empDetails = empDetails;
}
}
MyJson.java
package com.code.model;
import java.io.Serializable;
public class MyJson implements Serializable {
private String details;
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
}
MyJsonType.java
package com.code.model;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StringWriter;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MyJsonType implements UserType {
@Override
public int[] sqlTypes() {
return new int[]{Types.JAVA_OBJECT};
}
@Override
public Class<MyJson> returnedClass() {
return MyJson.class;
}
@Override
public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session,
final Object owner) throws HibernateException, SQLException {
final String cellContent = rs.getString(names[0]);
if (cellContent == null) {
return null;
}
try {
final ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(cellContent.getBytes("UTF-8"), returnedClass());
} catch (final Exception ex) {
throw new RuntimeException("Failed to convert String to Invoice: " + ex.getMessage(), ex);
}
}
@Override
public void nullSafeSet(final PreparedStatement ps, final Object value, final int idx,
final SessionImplementor session) throws HibernateException, SQLException {
if (value == null) {
ps.setNull(idx, Types.OTHER);
return;
}
try {
final ObjectMapper mapper = new ObjectMapper();
final StringWriter w = new StringWriter();
mapper.writeValue(w, value);
w.flush();
ps.setObject(idx, w.toString(), Types.OTHER);
} catch (final Exception ex) {
throw new RuntimeException("Failed to convert Invoice to String: " + ex.getMessage(), ex);
}
}
@Override
public Object deepCopy(final Object value) throws HibernateException {
try {
// use serialization to create a deep copy
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(value);
oos.flush();
oos.close();
bos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
return new ObjectInputStream(bais).readObject();
} catch (ClassNotFoundException | IOException ex) {
throw new HibernateException(ex);
}
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Serializable disassemble(final Object value) throws HibernateException {
return (Serializable) this.deepCopy(value);
}
@Override
public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
return this.deepCopy(cached);
}
@Override
public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
return this.deepCopy(original);
}
@Override
public boolean equals(final Object obj1, final Object obj2) throws HibernateException {
if (obj1 == null) {
return obj2 == null;
}
return obj1.equals(obj2);
}
@Override
public int hashCode(final Object obj) throws HibernateException {
return obj.hashCode();
}
}
MyPostgreSQL94Dialect.java
package com.code.model;
import java.sql.Types;
import org.hibernate.dialect.PostgreSQL94Dialect;
public class MyPostgreSQL94Dialect extends PostgreSQL94Dialect {
public MyPostgreSQL94Dialect() {
this.registerColumnType(Types.JAVA_OBJECT, "jsonb");
}
}
包信息.java
@org.hibernate.annotations.TypeDef(name = "MyJsonType", typeClass = com.comcast.model.MyJsonType.class)
package com.comcast.model;
CreateData.java(主类)
package com.code;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.code.model.Address;
import com.code.model.MyJson;
public class CreateData {
static SessionFactory sessFact;
static Session session;
static Transaction tr;
public static void main(String[] args) throws Exception {
init();
CreateData cd = new CreateData();
cd.insert();
}
public static void init() {
sessFact = HibernateUtil.getSessionFactory();
session = sessFact.getCurrentSession();
tr = session.beginTransaction();
}
public void insert() {
String json = "{" + "\"city\" : \"Lawrence\"," + "\"state\" : \"432 Essentric exmark street\"," + "\"zipcode\" : \"11111\"}";
MyJson j = new MyJson();
j.setDetails(json);
Address add = new Address();
add.setEmpDetails(j);
session.save(add);
tr.commit();
System.out.println("Successfully inserted");
sessFact.close();
}
}
错误:
Mar 01, 2018 7:30:33 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.1.0.Final}
Mar 01, 2018 7:30:33 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Mar 01, 2018 7:30:33 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Mar 01, 2018 7:30:33 PM org.hibernate.boot.jaxb.internal.stax.LocalXmlResourceResolver resolveEntity
WARN: HHH90000012: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/hibernate-configuration. Use namespace http://www.hibernate.org/dtd/hibernate-configuration instead. Support for obsolete DTD/XSD namespaces may be removed at any time.
Mar 01, 2018 7:30:33 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
Mar 01, 2018 7:30:33 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
Mar 01, 2018 7:30:33 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [org.postgresql.Driver] at URL [jdbc:postgresql://localhost:5433/sample_database]
Mar 01, 2018 7:30:33 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=postgres, password=****}
Mar 01, 2018 7:30:33 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Mar 01, 2018 7:30:33 PM org.hibernate.engine.jdbc.connections.internal.PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 10 (min=1)
Mar 01, 2018 7:30:34 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: com.comcast.model.MyPostgreSQL94Dialect
Mar 01, 2018 7:30:34 PM org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
Mar 01, 2018 7:30:34 PM org.hibernate.type.BasicTypeRegistry register
INFO: HHH000270: Type registration [java.util.UUID] overrides previous : org.hibernate.type.UUIDBinaryType@6a2f6f80
Enitial SessionFactory creation failedorg.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [MyJsonType]
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.comcast.HibernateUtil.<clinit>(HibernateUtil.java:30)
at com.comcast.CreateData.init(CreateData.java:29)
at com.comcast.CreateData.main(CreateData.java:21)
Caused by: org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [MyJsonType]
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.classForName(ClassLoaderServiceImpl.java:229)
at org.hibernate.boot.internal.ClassLoaderAccessImpl.classForName(ClassLoaderAccessImpl.java:62)
at org.hibernate.cfg.annotations.SimpleValueBinder.fillSimpleValue(SimpleValueBinder.java:521)
at org.hibernate.cfg.SetSimpleValueTypeSecondPass.doSecondPass(SetSimpleValueTypeSecondPass.java:25)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1621)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1579)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:418)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:87)
at com.comcast.HibernateUtil.<clinit>(HibernateUtil.java:24)
... 2 more
Caused by: java.lang.ClassNotFoundException: Could not load requested class : MyJsonType
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl$AggregatedClassLoader.findClass(ClassLoaderServiceImpl.java:217)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.classForName(ClassLoaderServiceImpl.java:226)
... 12 more
最佳答案
我自己的UserType遇到相同的奇怪错误。更有趣的是,仅在使用Gradle在命令行上执行测试时才会发生错误,而在IDE(IntelliJ)中执行测试时则不会发生。因为那个,我认为这是某种错误。
我通过将@TypeDef
注释从package-info.java
文件直接移动到实体文件来解决此问题:
@Entity
@Table(name = "address")
@TypeDef(name = "MyJsonType", typeClass = com.comcast.model.MyJsonType.class)
public class Address implements Serializable {
//...
}