Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DateTimeParseException reading Instant column with Persistence 3.2 #2191

Open
ajaypaul-ibm opened this issue Jul 2, 2024 · 5 comments
Open

Comments

@ajaypaul-ibm
Copy link
Contributor

Describe the bug
When Persistence 3.2 is used to query for an entity that has an attribute of type Instant, it gets a DateTimeParseException.

See test.jakarta.data.jpa.web.DemographicInfo, which has this attribute:

    @Column
    public Instant collectedOn;

and the following JPQL which read entities of that type:

SELECT o FROM DemographicInfo o WHERE (o.publicDebt BETWEEN ?1 AND ?2) ORDER BY o.publicDebt

The following exception is raised:

[6/19/24, 11:38:25:713 CDT] 00000051 id=00000000 eclipselink.ps                                               3 CWWKD0291W: Exception [EclipseLink-3002] (Eclipse Persistence Services - 5.0.0-B02.v202404111748): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [2007-04-30 11:00:00.0], of class [class java.lang.String], from mapping [org.eclipse.persistence.mappings.DirectToFieldMapping[collectedOn-->WLPDemographicInfo.COLLECTEDON]] with descriptor [RelationalDescriptor(test.jakarta.data.jpa.web.DemographicInfo --> [DatabaseTable(WLPDemographicInfo)])], could not be converted to [class java.time.Instant].
Internal Exception: java.time.format.DateTimeParseException: Text '2007-04-30 11:00:00.0' could not be parsed at index 10
[6/19/24, 11:38:25:713 CDT] 00000051 id=00000000 eclipselink.ps                                               3 throwable 
                                                                                                               Local Exception Stack: 
Exception [EclipseLink-3002] (Eclipse Persistence Services - 5.0.0-B02.v202404111748): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [2007-04-30 11:00:00.0], of class [class java.lang.String], from mapping [org.eclipse.persistence.mappings.DirectToFieldMapping[collectedOn-->WLPDemographicInfo.COLLECTEDON]] with descriptor [RelationalDescriptor(test.jakarta.data.jpa.web.DemographicInfo --> [DatabaseTable(WLPDemographicInfo)])], could not be converted to [class java.time.Instant].
Internal Exception: java.time.format.DateTimeParseException: Text '2007-04-30 11:00:00.0' could not be parsed at index 10
	at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConverted(ConversionException.java:95)
	at org.eclipse.persistence.internal.helper.ConversionManager.convertObject(ConversionManager.java:251)
	at org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform.convertObject(DatasourcePlatform.java:252)
	at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.getObjectValue(AbstractDirectMapping.java:659)
	at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.valueFromRow(AbstractDirectMapping.java:1271)
	at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.buildCloneFromRow(AbstractDirectMapping.java:238)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoWorkingCopyClone(ObjectBuilder.java:2109)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:2362)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:956)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInternal(ObjectBuilder.java:842)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:797)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:775)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:924)
	at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:987)
	at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:598)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1297)
	at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:934)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1256)
	at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:485)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1344)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:3015)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1841)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1823)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1788)
	at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:263)
	at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:480)
	at io.openliberty.data.internal.persistence.RepositoryImpl.invoke(RepositoryImpl.java:909)
	at jdk.proxy11/jdk.proxy11.$Proxy77.findByPublicDebtBetween(Unknown Source)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
	at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:109)
	at test.jakarta.data.jpa.web.Demographics$210985159$Proxy$_$$_WeldClientProxy.findByPublicDebtBetween(Unknown Source)
	at test.jakarta.data.jpa.web.DataJPATestServlet.testBigDecimal(DataJPATestServlet.java:286)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at componenttest.app.FATServlet.doGet(FATServlet.java:74)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:633)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:723)
	at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:169)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.time.format.DateTimeParseException: Text '2007-04-30 11:00:00.0' could not be parsed at index 10
	at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2108)
	at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:2010)
	at java.base/java.time.Instant.parse(Instant.java:398)
	at org.eclipse.persistence.internal.helper.ConversionManager.convertObjectToInstant(ConversionManager.java:863)
	at org.eclipse.persistence.internal.helper.ConversionManager.convertObject(ConversionManager.java:196)
	... 63 more

Steps to Reproduce
Re-enable test.jakarta.data.jpa.web.DataJPATestServlet.testBigDecimal() and test.jakarta.data.jpa.web.DataJPATestServlet.testBigInteger(), which, despite their names, are also testing Instant. These had to be disabled when switching the server.xml from persistence-3.1 to persistence-3.2.

Expected behavior
Successful retrieval of the entity, as happens with Persistence 3.1.

Diagnostic information:

OpenLiberty Version: latest in development
Affected feature(s) persistence-3.2, which breaks data-1.0
Java Version:

java.home = /Users/njr/drivers/jdk-21.jdk/Contents/Home
java.version = 21
java.runtime = OpenJDK Runtime Environment (21+35-2513)
os = Mac OS X (14.5; aarch64) (en_US)

server.xml configuration - refer to test case

@rfelcman
Copy link
Contributor

In the attachment You can find my test case which is passing. I don't see any bug as it described above.
Important files from test case are are
persistence.xml - see persistence unit test-jpa-pu-ddl from there. Test tables are created automatically by EclipseLink
You can enable/disable various DBs under persistence unit test-jpa-pu-ddl. Don't forget update connection info with Your environment.
DemographicInfoEntity.java - entity see

@Column(columnDefinition = "TIMESTAMP")
public Instant collectedOn;

TestDemographicInfoBug2191.java_ - test
jpa-bug-2243-JPQLSELECTQueryReturnsIncorrectResults.tar.gz

Feel free to modify attached test to demonstrate bug and upload there updated version.
But at this moment I don't see any issue there.

@pardhivkrishna
Copy link

Hi @rfelcman , I have modified the test to demonstrate the bug.
I inserted invalid data into the DemographicInfo table to simulate a scenario with an incompatible timestamp format for the collectedOn field. Instead of using

DemographicInfo US2022 = DemographicInfo.of(2022, 4, 29, 132250000, 6526909395140.41, 23847245116757.60);
DemographicInfo US2007 = DemographicInfo.of(2007, 4, 30, 121090000, 3833110332444.19, 5007058051986.64);

tx.begin();
em.persist(US2022);
em.persist(US2007);
tx.commit();

I tried out insertion using a native query as shown below

tx.begin();
em.createNativeQuery("INSERT INTO DemographicInfo (id, collectedOn, publicDebt, intragovernmentalDebt, numFullTimeWorkers) " +
                     "VALUES (1, '2007-04-30 21:30:00.0', 5007058051986.64, 3833110332444.19, 121090000)")
        .executeUpdate();
tx.commit();

I haven't explicitly specified the columnDefinition = "TIMESTAMP", in that case Instant is being mapped to VARCHAR(255) by default instead of TIMESTAMP which later causes DateTimeParseException.
jpa-bug-2191-DateTimeParseException.zip
I am not able to locate the source of default column definitions in EclipseLink code base.
Could you provide any hints or guidance on how to proceed? Thank you for the help.

@rfelcman
Copy link
Contributor

Sorry, but You want in this case from EclipseLink to read/convert date/time which is stored in DB VARCHAR in some formatting into java java.time.Instant. But this is locale dependent. E.g. in Czech Republic we have different date format.
So for invalid input '2007-04-30 21:30:00.0' there is correct java.time.format.DateTimeParseException.

@njr-11
Copy link
Contributor

njr-11 commented Dec 13, 2024

@pardhivkrishna you should not be using native query with hard code string values to try to reproduce the bug the error that Jakarta Data tests are seeing. Jakarta Data does not use native query or supply the values as strings. Jakarta Data uses entityManager.persist(entity), supplying an entity object that has a field/property of type Instant and does not force any particular columnDefinition, letting it default to whatever EclipseLink chooses when it autocreates the tables for us.

@Entity
public class DemographicInfo {

    @Column
    public Instant collectedOn;

    ...

Reproduction attempts that hard code string literals into a native query or enforce a particular columnDefinition into the entity definition are not faithfully reproducing the error that was found by our Jakarta Data tests.

@pardhivkrishna
Copy link

Hello @rfelcman , I have modified the test using entityManager.persist(entity) as told by @njr-11 .

Here's the updated version of the test:
2191 DateTimeParseException.zip

And I am getting the DateTimeParseException as

Exception [EclipseLink-3002] (Eclipse Persistence Services - 5.0.0-B03.v202409121024-4a7149f0cd04d7466837d70f68abb743c88acb83): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [2007-04-30 21:30:00], of class [class java.lang.String], from mapping [org.eclipse.persistence.mappings.DirectToFieldMapping[collectedOn-->DEMOGRAPHICINFO.COLLECTEDON]] with descriptor [RelationalDescriptor(com.oracle.jpa.bugtest.domain.DemographicInfo --> [DatabaseTable(DEMOGRAPHICINFO)])], could not be converted to [class java.time.Instant].
Internal Exception: java.time.format.DateTimeParseException: Text '2007-04-30 21:30:00' could not be parsed at index 10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants