1

I am migrating my Quarkus project from the classic Hibernate ORM to Hibernate Reactive and I faced a problem with JSONB field mapping.

Here is the entity:

@Entity
@TypeDef(name = JsonTypes.JSON_BIN, typeClass = JsonBinaryType::class)
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "myEntityIdGenerator")
    @SequenceGenerator(name = "myEntityIdGenerator", sequenceName = "my_entity_id_seq", allocationSize = 10)
    var id: Long? = null

    // Usage of a plain JsonNode instead of a mapped class is intentional, 
    // as the app receives a request with raw JSON data and should store it without any processing
    @Type(type = JsonTypes.JSON_BIN)
    @NotNull
    lateinit var jsonData: JsonNode
}

The project has the io.quarkiverse.hibernatetypes:quarkus-hibernate-types:0.2.0 dependency to handle JSON types.

This code worked fine with blocking Hibernate API, but when trying to persist a MyEntity using the Hibernate Reactive, I get the following exception:

io.vertx.core.impl.NoStackTraceThrowable: Parameter at position[1] with class = [com.fasterxml.jackson.databind.node.ObjectNode] and value = [{"field1":"some value"}] can not be coerced to the expected class = [java.lang.Object] for encoding.

Is this a bug or custom types should be handled differently while using Hibernate Reactive?

2 Answers 2

6

Hibernate Types is not compatible with Hibernate Reactive.

But you have three options to map a Json with Hibernate Reactive:

  1. Use io.vertx.core.json.JsonObject
  2. Map it as String and use a converter
  3. Create a UserType

1. JsonObject

Example with io.vertx.core.json.JsonObject:

    @Entity
    private static class EntityWithJson {

        ...

        private JsonObject jsonObj;

...
}

You can see a working example in the repository: JsonTypeTest

2. Using a converter

Example using a converter:

class EntityWithJson {

        @Column(columnDefinition = "json")
        @Convert(converter = StringToJson.class)
        private String json;
...
}

@Converter
public class StringToJson implements AttributeConverter<String, JsonObject> {

    @Override
    public JsonObject convertToDatabaseColumn(String string) {
        if (string == null) {
            return null;
        }
        return new JsonObject(string);
    }

    @Override
    public String convertToEntityAttribute(JsonObject dbData) {

        if (dbData == null) {
            return null;
        }
        return dbData.encodePrettily();
    }
}

You can see a working example in the repository: JsonTypeTest

3. UserType

class EntityWithJson {


        @Type(type="org.example.Json")
        @Column(columnDefinition = "json")
        private JsonObject jsonObj;

}

package org.example

public class Json implements UserType {

   // ... Implementation left out for brevity
}

You can see a working example in the repository: UserJsonTypeTest

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for such an exhaustive answer. The JsonObject field approach seems OK to me, but, unfortunately, the io.vertx.core.json.JsonObject does not implement Serializable, so when I put the @Cacheable annotation on my entity class, I get this exception: ClassCastException: class io.vertx.core.json.JsonObject cannot be cast to class java.io.Serializable.
I think I would map it as a string in that case
I ended up implementing the UserType, handling the serialization via assemble() and disassemble() methods. Here is my solution: gist.github.com/Ultranium/2caaa4899ad117647f59abf690389dcd
Hello after trying the Use a converter i managed to make my application work but what about jsonB with Array? because this was just a simple json but when i try the same with array i keep failing
Would you be able to create a test case that I can run? I don't have a solution on top of my head
|
3

To store a field with postgres type JSONB, we can use the annotation :

@JdbcTypeCode(SqlTypes.JSON)

This will automatically create the table column with JsonB data type.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.