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

Use default ObjectMapper in FormatMappers Configuration for Hibernate ORM's JSONType #32029

Closed
jcgehrke opened this issue Mar 22, 2023 · 18 comments · Fixed by #35113
Closed

Use default ObjectMapper in FormatMappers Configuration for Hibernate ORM's JSONType #32029

jcgehrke opened this issue Mar 22, 2023 · 18 comments · Fixed by #35113
Labels
area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE env/windows Impacts Windows machines kind/enhancement New feature or request
Milestone

Comments

@jcgehrke
Copy link

Describe the bug

Hi,
when using

@JdbcTypeCode(SqlTypes.JSON)
List<SomeObject> someObjects;

from Hibernate 6 and Jackson the JacksonJsonFormatMapper is used, which uses an ObjectMapper from Jackson.
This ObjectMapper is not configured like the global ObjectMapper and doesn't see the jsr310 dependency on the path.
As result types like LocalDate in the type of the Colume raise an exception.

Expected behavior

It would be nice, if the global ObjectMapper is used or an Method to supply your own
Alternatively use an ObjectMapper that is configured to respect jsr310. This would mitigate most of the problems.

Actual behavior

@JdbcTypeCode(SqlTypes.JSON)
List<SomeObject> someObjects;

raises an exception, if SomeObject contains a LocalDate.

How to Reproduce?

Setup a Quarkus project with Hibernate 6.

Write an Entity with

@JdbcTypeCode(SqlTypes.JSON)
List<SomeObject> someObjects;

where SomeObject is a pojo with a member of type LocalDate.

Persisten an the entity with data.

Output of uname -a or ver

windows32 Name 2.6.2 9200 i686-pc Intel unknown MinGW

Output of java -version

openjdk 11.0.7 2020-04-14 OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.7+10) OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.7+10, mixed mode)

GraalVM version (if different from Java)

Not used

Quarkus version or git rev

3.0.0.Alpha6

Build tool (ie. output of mvnw --version or gradlew --version)

Maven 3.8.4

Additional information

No response

@jcgehrke jcgehrke added the kind/bug Something isn't working label Mar 22, 2023
@quarkus-bot quarkus-bot bot added area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE env/windows Impacts Windows machines labels Mar 22, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Mar 22, 2023

/cc @Sanne (hibernate-orm), @gsmet (hibernate-orm), @yrodiere (hibernate-orm)

@yrodiere
Copy link
Member

yrodiere commented Mar 22, 2023

Fair point. From what I can see we would need to register our own org.hibernate.type.format.FormatMapper in order to do that.

In the meantime, an (unsupported) workaround would be to set your own format mapper:

quarkus.hibernate-orm.unsupported-properties."hibernate.type.json_format_mapper" = com.acme.MyFormatMapper

The implementation would be something like that:

public class MyFormatMapper implements org.hibernate.type.format.FormatMapper {

	private final org.hibernate.type.format.FormatMapper delegate = new JacksonJsonFormatMapper( Arc.container().instance(ObjectMapper.class).get() );

	public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
		delegate.fromString(charSequence, javaType, wrapperOptions);
	}


	public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
		delegate.toString(value, javaType, wrapperOptions);
	}

}

@jcgehrke
Copy link
Author

Thanks for the workaround. It seems to work, I'm running in some other unreleated issues now.
An official api or a fix would still be appreciated. :)

@yrodiere yrodiere added kind/enhancement New feature or request and removed kind/bug Something isn't working labels Mar 22, 2023
@yrodiere yrodiere changed the title ObjectMapper Configuration not respected in FormatMappers Configuration for Hibernate JSONType Use default ObjectMapper in FormatMappers Configuration for Hibernate ORM's JSONType Mar 22, 2023
@yrodiere
Copy link
Member

An official api or a fix would still be appreciated. :)

Sure, I'll get to it... eventually. My backlog is not small :)

If anyone wants to contribute this, the right place to start would probably be io.quarkus.hibernate.orm.runtime.boot.FastBootMetadataBuilder#mergeSettings. And you might be able to add tests in the integration tests of a DB that actually supports JSON, e.g. integration-tests/jpa-postgresql/src/main/java/io/quarkus/it/jpa/postgresql.

@joggeli34
Copy link
Contributor

This would be very nice now that quarkus 3.0 is released.

@yrodiere
Copy link
Member

Agreed.

If anyone wants to contribute this, the right place to start would probably be io.quarkus.hibernate.orm.runtime.boot.FastBootMetadataBuilder#mergeSettings. And you might be able to add tests in the integration tests of a DB that actually supports JSON, e.g. integration-tests/jpa-postgresql/src/main/java/io/quarkus/it/jpa/postgresql.

@yrodiere
Copy link
Member

yrodiere commented May 5, 2023

@geoand:

@Sanne where is this ObjectMapper integration located?

There is none at the moment, ORM creates its own object mapper. See the discussion above for details.

@geoand
Copy link
Contributor

geoand commented May 5, 2023

Ah, okay. I'll have a look next week

@gsmet
Copy link
Member

gsmet commented May 5, 2023

I think we need to be a bit careful here as there's a good chance you might need a different mapper than the global one. We had several requests of being able to use different mapper configuration for different use cases.

@geoand
Copy link
Contributor

geoand commented May 5, 2023

Yeah, we would need to perform some checks

@geoand
Copy link
Contributor

geoand commented May 8, 2023

As there is a workaround for the time being, I am going to push this a little further back on my TODO list :)

@manuelserradev
Copy link

I'm adding a +1 on this issue since we're also impacted by this behaviour - and the workaround proposed scream'd "I'll be unstable and not production ready".

What's the canonical (and maybe supported) approach to reuse the same OM on the ORM side?

@iqnev
Copy link
Contributor

iqnev commented Nov 22, 2023

Hello everyone, any updates on the aforementioned issue? @marko-bekhta

@yrodiere
Copy link
Member

Hello. See #35113 . It's in the works.

@quarkus-bot quarkus-bot bot added this to the 3.7 - main milestone Nov 22, 2023
@iqnev
Copy link
Contributor

iqnev commented Nov 29, 2023

Hi @yrodiere attempted to implement your workaround #32029 (comment) while awaiting the official fix. The workaround functions seamlessly in JVM mode; however, in native mode, the application encounters an error, and the corresponding error message is as follows:
io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider","severity":"WARN","message":"Persistence-unit [<default>] sets unsupported properties. These properties may not work correctly, and even if they do, that may change when upgrading to a newer version of Quarkus (even just a micro/patch version). Consider using a supported configuration property before falling back to unsupported ones. If there is no supported equivalent, make sure to file a feature request so that a supported configuration property can be added to Quarkus, and more importantly so that the configuration property is tested regularly. Unsupported properties being set: [hibernate.type.json_format_mapper]","thread":"JPA Startup Thread

@yrodiere
Copy link
Member

Hey @iqnev. That's a warning, not an error? And I think (hope) it's self-explanatory.

@iqnev
Copy link
Contributor

iqnev commented Nov 29, 2023

@yrodiere yes, in native mode, the application fails to start, whereas in JVM mode, it starts correctly. I found the hidden error:

java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:101)
	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:111)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
	at io.quarkus.runner.GeneratedMain.main(Unknown Source)
Caused by: java.lang.RuntimeException: jakarta.persistence.PersistenceException: [PersistenceUnit: <default>] Unable to build Hibernate SessionFactory
	at io.quarkus.hibernate.orm.runtime.JPAConfig.startAll(JPAConfig.java:78)
	at io.quarkus.hibernate.orm.runtime.HibernateOrmRecorder.startAllPersistenceUnits(HibernateOrmRecorder.java:101)
	at io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits1868654632.deploy_0(Unknown Source)
	at io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits1868654632.deploy(Unknown Source)
	... 7 more
Caused by: jakarta.persistence.PersistenceException: [PersistenceUnit: <default>] Unable to build Hibernate SessionFactory
	at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.persistenceException(FastBootEntityManagerFactoryBuilder.java:126)
	at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:86)
	at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:74)
	at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
	at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
	at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:156)
	at io.quarkus.hibernate.orm.runtime.JPAConfig$1.run(JPAConfig.java:64)
	at java.base@17.0.9/java.lang.Thread.run(Thread.java:840)
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:807)
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:210)
Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Unable to resolve name [demo.commons.config.MyFormatMapper] as strategy [org.hibernate.type.format.FormatMapper]
	at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java:154)
	at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveStrategy(StrategySelectorImpl.java:236)
	at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveDefaultableStrategy(StrategySelectorImpl.java:180)
	at org.hibernate.boot.internal.SessionFactoryOptionsBuilder.determineJsonFormatMapper(SessionFactoryOptionsBuilder.java:781)
	at org.hibernate.boot.internal.SessionFactoryOptionsBuilder.<init>(SessionFactoryOptionsBuilder.java:298)
	at io.quarkus.hibernate.orm.runtime.recording.PrevalidatedQuarkusMetadata.buildSessionFactoryOptionsBuilder(PrevalidatedQuarkusMetadata.java:70)
	at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:81)
	... 8 more
Caused by: org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [demo.loadbookmark.commons.config.MyFormatMapper]
	at io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:38)
	at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java:150)
	... 14 more
Caused by: java.lang.ClassNotFoundException: demo.commons.config.MyFormatMapper
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:123)
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:87)
	at java.base@17.0.9/java.lang.Class.forName(DynamicHub.java:1322)
	at java.base@17.0.9/java.lang.Class.forName(DynamicHub.java:1311)
	at io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService.classForName(FlatClassLoaderService.java:36)

It's puzzling why the class cannot be loaded in native mode.

@iqnev
Copy link
Contributor

iqnev commented Nov 29, 2023

ahhh Require registration the MyFormatMapper for reflection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE env/windows Impacts Windows machines kind/enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants