34

Hibernate 5 does not support the PostgreSQL jsonb data type by default.

Is there any way to implement jsonb support for Hibernate + Spring JPA?

If there is a way, what are the pros and cons of using jsonb with Hibernate?

pants
  • 192
  • 13
Aventes
  • 569
  • 1
  • 8
  • 20

3 Answers3

49

Thanks Vlad Mihalcea we have such opportunity! )

He created hibernate-types lib:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.1.1</version>
</dependency> 

which adds a support of 'json', 'jsonb' and other types to Hibernate:

@Data
@NoArgsConstructor
@Entity
@Table(name = "parents")
@TypeDefs({
        @TypeDef(name = "string-array", typeClass = StringArrayType.class),
        @TypeDef(name = "int-array", typeClass = IntArrayType.class),
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class Parent implements Serializable {

    @Id
    @GeneratedValue(strategy = SEQUENCE)
    private Integer id;

    @Column(length = 32, nullable = false)
    private String name;

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private List<Child> children;

    @Type(type = "string-array")
    @Column(columnDefinition = "text[]")
    private String[] phones;

    public Parent(String name, List<Child> children, String... phones) {
        this.name = name;
        this.children = children;
        this.phones = phones;
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Child implements Serializable {
    private String name;
}

More info: 1, 2

Cepr0
  • 28,144
  • 8
  • 75
  • 101
  • Thanks @Cepr0 for the answer. Actually, does this library support search by an object field? As I can see this library is pretty raw and community not really big, is it reliable? – Aventes Mar 16 '18 at 18:31
  • 6
    @Aventes Vlad is one of the [Hibernate authors](http://stackoverflow.com/users/1025118/vlad-mihalcea) – Cepr0 Mar 16 '18 at 19:27
  • 2
    @Aventes The [Hibernate Types framework](https://github.com/vladmihalcea/hibernate-types) has over 750 GitHub stars and gets over 400k monthly downloads. So, the community is quite big because the Hibernate Types framework provides support for JSON, ARRAY, Inet, HStore, TSVector, DBs-specific Enums, YearMonth, and many other features. – Vlad Mihalcea Jun 09 '20 at 04:41
  • @VladMihalcea Why do the Hibernate not support these types? Because they are not standard sql type? – muasif80 Jun 10 '20 at 05:28
  • 3
    JSON and ARRAY are standard, but thry are not supported by all DBs that Hibernate supports. One day, it might support the. In the meantime, you csn use the Hibernate Types project. – Vlad Mihalcea Jun 10 '20 at 06:01
  • I tried to use these annotation directly on a JSONObject but get "java.lang.IllegalArgumentException: Cannot create TypeBindings for class org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImpl with 2 type parameters: class expects 0". Have you any clue ? – MilacH Jul 28 '20 at 12:45
  • javax.json.JsonObject I meant (sry). Same with Map – MilacH Jul 28 '20 at 13:05
6

@Cepr0-s answer is correct but although I got some issues with it. I was getting exception when trying to use it with PostgreSQL org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111. Way to solve this, in my case, was adding custom hibernate dialect. This resource might be helpful.

// CustomPostgreSQLDialect.java
public class CustomPostgreSQLDialect extends PostgreSQL10Dialect {

    public CustomPostgreSQLDialect() {
        super();
        registerHibernateType(Types.OTHER, StringArrayType.class.getName());
        registerHibernateType(Types.OTHER, IntArrayType.class.getName());
        registerHibernateType(Types.OTHER, JsonStringType.class.getName());
        registerHibernateType(Types.OTHER, JsonBinaryType.class.getName());
        registerHibernateType(Types.OTHER, JsonNodeBinaryType.class.getName());
        registerHibernateType(Types.OTHER, JsonNodeStringType.class.getName());
    }
}

-

# application.yml
spring:
  jpa:
    properties:
      hibernate:
        dialect: "com.test.CustomPostgreSQLDialect"
GROX13
  • 4,605
  • 4
  • 27
  • 41
4

Update for Hibernate 6+ (2022+)

With the advent of Hibernate 6, mapping to PostgreSQL JSON(B) has became possible out-of-the box.

One only needs to annotate the field with JdbcTypeCode(SqlTypes.JSON).

With non-typed JSON:

@Entity
public class Entity {
    ...
    @JdbcTypeCode(SqlTypes.JSON)
    private Map<String, String> payload;
    ...
}

(Although not every JSON will serialize into a Map).

With JSON which is serialized as a custom Java type:

public class Foo implements Serializable {
  
    private String strValue;
    private Long longValue;
  
    public String getStrValue() {
        return strValue;
    }
  
    public void setStringProp(String stringProp) {
        this.strValue = strValue;
    }
  
    public Long getLongValue() {
        return longProp;
    }
  
    public void setLongValue(Long longValue) {
        this.longValue = longValue;
    }
}


@Entity
public class Entity {
    ...
    @JdbcTypeCode(SqlTypes.JSON)
    private Foo fooJson;
    ...
}

Please see this article for more examples: https://thorben-janssen.com/persist-postgresqls-jsonb-data-type-hibernate/

dimnnv
  • 678
  • 3
  • 8
  • 21
  • Does not work. Despite @JdbcTypeCode(SqlTypes.JSON) on the entity field I am getting FIELD is of type jsonb but expression is of type bytea. Neither did @Type(JsonBinaryType.class) @Column(columnDefinition = "jsonb") help. Hibernate is just a massive pain. – Phil Aug 03 '23 at 15:32
  • What adds insult to the injury is Hibernate team's response to community complaints: https://stackoverflow.com/a/70294493/4125622 – Phil Aug 03 '23 at 15:38