我试图通过使用“带有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 {
 //...
}

10-07 23:23