Как использовать JPA для столбца типа JSON в сущности типа MapJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Как использовать JPA для столбца типа JSON в сущности типа Map

Сообщение Anonymous »

У меня есть вариант использования, в котором я хочу сохранить некоторую конфигурацию (пары имя флага + логическое состояние) в БД. Я выбрал способ сохранить его в формате JSON по внутренним причинам.
Мне удается сохранить данные, но получить сохраненные данные не удается.
Упрощенная таблица для хранения данных

Код: Выделить всё

CREATE TABLE "SCHEMA"."CONFIG" (
"ID" NUMBER(38,0) NOT NULL ENABLE,
"ITEMS" JSON DEFAULT '' NOT NULL ENABLE,
CONSTRAINT "PK_CONFIG" PRIMARY KEY ("ID")
)
Связанный объект, который должен отражать таблицу БД:

Код: Выделить всё

@Entity
@Table(name = "CONFIG")
@SequenceGenerator(name = "ConfigIdGenerator", sequenceName = "CONFIG_ID_SEQ", allocationSize = 1)
public class ConfigEntity {

private long id;
private Map items;

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ConfigIdGenerator")
@Column(name = "ID", nullable = false)
@Id
public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

@Convert(converter = ConfigItemsConverter.class)
@Column(name = "ITEMS", nullable = false, columnDefinition = "JSON")
public Map getItems() {
return items;
}

public void setItems(Map items) {
this.items = items;
}
}
Использованный конвертер, который должен обеспечить преобразование MAP STRING:

Код: Выделить всё

@Converter
public class ConfigItemsConverter implements AttributeConverter {

private static final ObjectMapper MAPPER = new ObjectMapper();

@Override
public String convertToDatabaseColumn(Map value) {
try {
return MAPPER.writeValueAsString(value);
} catch (JsonProcessingException ex) {
// Should not happen. Map values should be in correct format due to generics.
ex.printStackTrace();
}
return null;
}

@Override
public Map convertToEntityAttribute(String dbValue) {
try {
return MAPPER.readValue(dbValue, new TypeReference() {});
} catch (JsonProcessingException ex) {
// Should not happen. DB data are in JSON format due to JSON datatype
ex.printStackTrace();
}
return null;
}

}
Когда я пытаюсь сохранить новые данные, все работает правильно. Конвертер вызывает метод ConvertToDatabaseColumn, выполняет преобразование и данные сохраняются в БД.
С другой стороны, когда я пытаюсь получить эти данные (

Код: Выделить всё

query.setMaxResults(1).getResultStream()...
), я получаю исключение

Код: Выделить всё

jakarta.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 4.0.2.v202306161219): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Invalid column type: getOracleObject not implemented for class oracle.jdbc.driver.T4CJsonAccessor
Error Code: 17004
Call: SELECT * FROM (SELECT /*+ FIRST_ROWS */ a.*, ROWNUM rnum  FROM (SELECT t1.ID AS a1, t1.ITEMS AS a2 FROM MAINMENU_SETTING t1 ) a WHERE ROWNUM  ?
bind => [1, 0]
Query: ReadAllQuery(name="ConfigEntity.FIND_ALL" referenceClass=ConfigEntity sql="SELECT * FROM (SELECT /*+ FIRST_ROWS */ a.*, ROWNUM rnum  FROM (SELECT t1.ID AS a1, t1.ITEMS AS a2 FROM MAINMENU_SETTING t1 ) a WHERE ROWNUM  ?")
at org.eclipse.persistence.internal.jpa.QueryImpl.getDetailedException(QueryImpl.java:392) ~[org.eclipse.persistence.jpa-4.0.2.jar:?]
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:265) ~[org.eclipse.persistence.jpa-4.0.2.jar:?]
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:483) ~[org.eclipse.persistence.jpa-4.0.2.jar:?]
at jakarta.persistence.TypedQuery.getResultStream(TypedQuery.java:93) ~[jakarta.persistence-api-3.2.0.jar:3.2.0]
...
Caused by: java.sql.SQLException: Invalid column type: getOracleObject not implemented for class oracle.jdbc.driver.T4CJsonAccessor
at oracle.jdbc.driver.GeneratedAccessor.getOracleObject(GeneratedAccessor.java:1221) ~[ojdbc11-21.10.0.0.jar:21.10.0.0.0]
at oracle.jdbc.driver.JsonAccessor.getObject(JsonAccessor.java:263) ~[ojdbc11-21.10.0.0.jar:21.10.0.0.0]
at oracle.jdbc.driver.GeneratedStatement.getObject(GeneratedStatement.java:196) ~[ojdbc11-21.10.0.0.jar:21.10.0.0.0]
at oracle.jdbc.driver.GeneratedScrollableResultSet.getObject(GeneratedScrollableResultSet.java:334) ~[ojdbc11-21.10.0.0.jar:21.10.0.0.0]
at oracle.ucp.jdbc.proxy.oracle.ResultSetProxy.getObject(ResultSetProxy.java:152) ~[ucp11-21.10.0.0.jar:21.10.0.0.0]
at oracle.ucp.jdbc.proxy.oracle$1ucp$1jdbc$1proxy$1oracle$1ResultSetProxy$2oracle$1jdbc$1internal$1OracleResultSet$$$Proxy.getObject(Unknown Source) ~[ucp11-21.10.0.0.jar:21.10.0.0.0]
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.getObjectFromResultSet(DatabasePlatform.java:1230) ~[org.eclipse.persistence.core-4.0.2.jar:?]
at org.eclipse.persistence.platform.database.OraclePlatform.getObjectFromResultSet(OraclePlatform.java:575) ~[org.eclipse.persistence.core-4.0.2.jar:?]
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.getObject(DatabaseAccessor.java:1375) ~[org.eclipse.persistence.core-4.0.2.jar:?]
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.fetchRow(DatabaseAccessor.java:1094) ~[org.eclipse.persistence.core-4.0.2.jar:?]
Метод преобразования ConvertToEntityAttribute никогда не вызывается.
Можете ли вы подсказать мне, почему преобразование работает только в одном направлении? Чего не хватает и как это исправить?
Спасибо

Подробнее здесь: https://stackoverflow.com/questions/793 ... f-type-map
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»