PostgreSQL throws "column is of type jsonb but expression is of type bytea" with JPA and Hibernate
Asked Answered
R

4

21

This is my entity class that is mapped to a table in postgres (9.4) I am trying to store metadata as jsonb type in the database

@Entity
@Table(name = “room_categories”)
@TypeDef(name = “jsonb”, typeClass = JsonBinaryType.class)
public class RoomCategory extends AbstractEntity implements Serializable {
    private String name;
    private String code;
    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private Metadata metadata;

}

This is the metadata class:

public class Metadata implements Serializable {
    private String field1;
    private String field2;

}

I have used following migration file to add jsonb column:

databaseChangeLog:
– changeSet:
id: addColumn_metadata-room_categories
author: arihant
changes:
– addColumn:
schemaName: public
tableName: room_categories
columns:
– column:
name: metadata
type: jsonb

I am getting this error while creating the record in postgres: ERROR: column “metadata” is of type jsonb but expression is of type bytea Hint: You will need to rewrite or cast the expression.

This is the request body i am trying to persist in db:

  {
    “name”: “Test102”,
    “code”: “Code102”,
    “metadata”: {
    “field1”: “field11”,
    “field2”: “field12”
    }
    }

Please help how to convert bytea type to jsonb in java spring boot app

Rhetic answered 19/12, 2018 at 9:13 Comment(2)
possible duplicate of : #20402219... kindly visit above link.Saleswoman
@Arihant Jain: I am too facing such issue. Did u resolved urs?Hawes
V
17

Simply convert your object by an ObjectMapper to a json string and then use (::jsonb) as cast to jsonb type:

INSERT INTO room_categories (name, code, metadata)
    VALUES (?, ?, ? ::jsonb ); 

(you will need to use native queries to query data stored as jsonb)

Valerle answered 7/7, 2020 at 11:59 Comment(1)
This should be the answer. It helped fix the issue.Mucoviscidosis
S
11

if you use the JpaRespository save interface method, you can add the cast method above the issue property

@ColumnTransformer(write = "?::jsonb")
private Metadata metadata;
Sundstrom answered 20/10, 2023 at 13:33 Comment(0)
M
4

The cause of the error

You could get this PostgreSQL:

ERROR: column “metadata” is of type jsonb but expression is of type bytea Hint: You will need to rewrite or cast the expression.

if you are executing a native SQL DML statement.

Native SQL DML statement

For instance, let's assume you want to do something like this:

int updateCount = entityManager.createNativeQuery("""
    UPDATE
        room_categories
    SET
        metadata = :metadata
    WHERE
        code = :code AND
        metadata ->> 'field1' is null            
    """)
.setParameter("code ", "123-ABC")
.setParameter(
    "metadata",
    new Metadata()
        .setField1("ABC")
        .setField2("123")
)
.executeUpdate();

The bytea type stands for byte array, and, since the Metadata type implements the Serializable interface, Hibernate falls back to using the SerializableType when no other type is more appropriate.

But, since you cannot bind a byte array to a jsonb column, PostgreSQL throws the aforementioned error.

The fix

To fix it, we have to set the JsonBinaryType explicitly using the Hibernate-specific setParameter Query method:

int updateCount = entityManager.createNativeQuery("""
    UPDATE
        room_categories
    SET
        metadata = :metadata
    WHERE
        code = :code AND
        metadata ->> 'field1' is null            
    """)
.setParameter("code ", "123-ABC")
.unwrap(org.hibernate.query.Query.class)
.setParameter(
    "metadata",
    new Metadata()
        .setField1("ABC")
        .setField2("123"),
    JsonBinaryType.INSTANCE
)
.executeUpdate();

First, we had to unwrap the JPA Query to a Hibernate org.hibernate.query.Query and call the setParameter method that takes a Hibernate Type instance.

Now, Hibernate will know that the metadata parameter needs to be handled by the JsonBinaryType, and not by the SerializableType.

Medievalism answered 19/12, 2018 at 9:24 Comment(1)
we had exactly this solution in our code for a while, now after update to springboot 2 and hibernate 6 it stopped working.Courtier
E
1

Im coming a few years later but maybe useful for others:

In my case I fixed this problem by adding the following parameter to the connection string:

stringtype=unspecified

Elfreda answered 9/2 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.