Использование типа 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. 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.