Использование типа PostgreSQL JSONB с Hibernate Reactive

Я переношу свой проект Quarkus с классического Hibernate ORM на Hibernate Reactive и столкнулся с проблемой сопоставления полей JSONB.

Вот сущность:

      @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
}

В проекте естьio.quarkiverse.hibernatetypes:quarkus-hibernate-types:0.2.0зависимость для обработки типов JSON.

Этот код отлично работал с блокировкой Hibernate API, но при попытке сохранитьMyEntityиспользуя Hibernate Reactive, я получаю следующее исключение:

      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.

Является ли это ошибкой или пользовательские типы должны обрабатываться по-разному при использовании Hibernate Reactive?

2 ответа

Hibernate Types несовместимы с Hibernate Reactive.

Но у вас есть три варианта сопоставления Json с Hibenrnate Reactive:

  1. Использовать
  2. Сопоставьте его как строку и используйте конвертер
  3. Создать тип пользователя

1. JsonObject

Пример сio.vertx.core.json.JsonObject:

          @Entity
    private static class EntityWithJson {

        ...

        private JsonObject jsonObj;

...
}

Вы можете увидеть рабочий пример в репозитории:

2. Использование конвертера

Пример использования конвертера:

      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();
    }
}

Вы можете увидеть рабочий пример в репозитории: JsonTypeTestJsonTypeTest

3. Тип пользователя

      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
}

Вы можете увидеть рабочий пример в репозитории: UserJsonTypeTest

Чтобы сохранить поле с типом Postgres JSONB, мы можем использовать аннотацию:

@JdbcTypeCode(SqlTypes.JSON)

Это автоматически создаст столбец таблицы с типом данных JsonB.

Другие вопросы по тегам