Я хочу добавить поддержку для Java 8 Date/Time API (JSR-310) в моем приложении с поддержкой JPA.
Ясно, что JPA 2.1 не поддерживает API-интерфейс Java 8 Date/Time.
В качестве обходного пути наиболее распространенным советом является использование AttributeConverter
.
В моем существующем приложении я изменил свои сущности, чтобы использовать типы LocalDate
/LocalDateTime
для полей сопоставления столбцов и добавить для них устаревшие setter/getters для java.util.Date
.
Я создал соответствующие классы AttributeConverter
.
Мое приложение теперь терпит неудачу при использовании Query.setParameter()
с экземплярами java.util.Date
(оно работало до перехода на новый API).
Похоже, JPA ожидает новых типов дат и не конвертирует их на лету.
Я ожидал, что если передать аргумент в setParameter()
типа, для которого был зарегистрирован AttributeConverter
, он будет автоматически преобразован конвертером.
Но это, похоже, не так, по крайней мере, не используя EclipseLink 2.6.2
:
java.lang.IllegalArgumentException: You have attempted to set a value of type class java.util.Date for parameter closeDate with expected type of class java.time.LocalDate from query string SELECT obj FROM [...]
at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:937) ~[eclipselink-2.6.2.jar:2.6.2.v20151217-774c696]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:593) ~[eclipselink-2.6.2.jar:2.6.2.v20151217-774c696]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:1) ~[eclipselink-2.6.2.jar:2.6.2.v20151217-774c696]
[...]
Вопросы
- Является ли это поведение ожидаемым? Я что-то пропустил?
- Существует ли способ использовать новые типы дат как поля без нарушения существующего кода?
- Как вы применили с переходом на новый API Date/Time в JPA?
ОБНОВЛЕНИЕ:
Однако, похоже, что по крайней мере с использованием EclipseLink нестандартные типы, для которых существует AttributeConverter
, не полностью поддерживаются:
В рамках запросов JPQL ни один тип поля или преобразованный тип базы данных не могут использоваться в качестве параметра.
При использовании преобразованного типа базы данных происходит описанное выше исключение.
При использовании фактического типа поля (например, LocalDate
) он напрямую передается драйверу jdbc, который не знает этого типа:
Caused by: java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:10495)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9974)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:10799)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:10776)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:241)
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.setParameterValueInDatabaseCall(DatabasePlatform.java:2506)
Я бы ожидал, что EclipseLink преобразует тип поля в тип java.sql с помощью AttributeConverter. (см. также этот отчет об ошибке: https://bugs.eclipse.org/bugs/show_bug.cgi?id=494999)
Это приводит нас к самому важному вопросу № 4:
- Есть ли способ обхода/решения для поддержки полей даты java 8 с использованием
EclipseLink
, , включая возможность использования параметров запроса в таком поле?
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ