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 JsonTypeInfo.Value for annotation handling #3953

Merged

Conversation

JooHyukKim
Copy link
Member

(original PR is #3942, but had to create a new branch due to complex git rebase conflicts)

As a part of #3943, this PR applies JsonTypeInfo.Value usages from Jackson 3.0

@cowtowncoder
Copy link
Member

Looks good so far @JooHyukKim ! One more thing that'd be great to check before I merge -- would it be possibly to locally build 2.16.0-SNAPSHOT from this PR/branch, and see that jackson-module-jaxb-annotations and jackson-dataformat-xml 2.16 branch would also build successfully? Or if not, jaxb-annotations one probably requires changes (I don't remember if they needed for 3.0).

If not, I can try this myself later tonight.

@JooHyukKim
Copy link
Member Author

JooHyukKim commented May 24, 2023

Looks good so far @JooHyukKim ! One more thing that'd be great to check before I merge -- would it be possibly to locally ...

Will do in an hour or two and let you know 👍🏻

@cowtowncoder good call on building locally 👍🏻 Local build is producing failing tests. ATM trying to figure out why

Leaving here link to Test branch for reference.

Andddd the failing test.

image

EDIT: Found a fix and described it in below comment.

@@ -1568,6 +1568,17 @@ protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() {
return new StdTypeResolverBuilder();
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did put this back in here after realizing that removing this method will break extensions such as Xml

@JooHyukKim
Copy link
Member Author

JooHyukKim commented May 24, 2023

@cowtowncoder good call on building locally 👍🏻 Local build is producing failing tests. ATM trying to figure out why

Phew, took long journey going back and forth projects and versions trying to debug 😂

So result,

- jackson-dataformat-xml module
~~~- Breaks.~~
- But with I made a 👉🏼🔗 draft PR demonstrating a fix, ---seems doable in my opinion, if we can find a way to prevent regression for extensions such as jackson-dataformat-xml.
- jackson-module-jaxb-annotations
- I haven't found time for this today.
- I need help with this, as I have no experience with it (though probably quite similar)

EDIT

  • jackson-dataformat-xml module : breaks, but fix here 👉🏼🔗 draft PR demonstrating a fix
  • jackson-module-jaxb-annotations : Build successfully

So, this is a breaking change for usage case like XML module. Do you think we can handle this in a safe way, @cowtowncoder ?

@cowtowncoder
Copy link
Member

@JooHyukKim It's ok to have temporary breakage during changes, although that won't prevent issues across different minor versions of components which we try to limit. For example, ideally 2.15 of jackson-dataformat-xml would work with newer jackson-databind (like 2.16) (but not the other way around). This may not be something we can always maintain.

@cowtowncoder cowtowncoder merged commit feb4ce1 into FasterXML:2.16 May 26, 2023
3 checks passed
@cowtowncoder cowtowncoder changed the title Apply JsonTypeInfo.Value usages from Jackson 3.0 Use JsonTypeInfo.Value for annotation handling May 26, 2023
cowtowncoder added a commit that referenced this pull request May 26, 2023
@cowtowncoder cowtowncoder added this to the 2.16.0 milestone May 26, 2023
@JooHyukKim
Copy link
Member Author

@JooHyukKim It's ok to have temporary breakage during changes, although that won't prevent issues across different minor versions of components which we try to limit. For example, ideally 2.15 of jackson-dataformat-xml would work with newer jackson-databind (like 2.16) (but not the other way around). This may not be something we can always maintain.

Right, thank you fhr the explanation! 🙏🏼🙏🏼

@JFCote
Copy link

JFCote commented Dec 8, 2023

Hi @JooHyukKim and @cowtowncoder !

I updated my code to version 2.16.0 and instantly started to receive a ton of exceptions in my code. I checked the differences between 2.15.3 and 2.16.0 and tracked back the problem to this PR.
In my code, I save "commands" to the database in a field. This command is json and there are tons of possible commands but they all share the same basic structure and before this update there was no problem to handle this situation.

Now, I receive this error:

java.lang.ClassNotFoundException: com.fasterxml.jackson.annotation.JsonTypeInfo$Value
	at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector.findPolymorphicTypeInfo(JacksonAnnotationIntrospector.java:670)
	at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector._findTypeResolver(JacksonAnnotationIntrospector.java:1579)
	at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector.findTypeResolver(JacksonAnnotationIntrospector.java:677)
	at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findTypeResolver(AnnotationIntrospectorPair.java:253)
	at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findTypeDeserializer(BasicDeserializerFactory.java:1807)
	at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:675)
	at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:5030)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4900)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3846)
	at io.hypersistence.utils.hibernate.type.util.ObjectMapperWrapper.fromString(ObjectMapperWrapper.java:86)
	at io.hypersistence.utils.hibernate.type.json.internal.JsonJavaTypeDescriptor.fromString(JsonJavaTypeDescriptor.java:133)
	at io.hypersistence.utils.hibernate.type.json.internal.JsonJavaTypeDescriptor.wrap(JsonJavaTypeDescriptor.java:191)
	at io.hypersistence.utils.hibernate.type.json.internal.AbstractJsonJdbcTypeDescriptor$1.doExtract(AbstractJsonJdbcTypeDescriptor.java:29)
	at org.hibernate.type.descriptor.jdbc.BasicExtractor.extract(BasicExtractor.java:44)
	at io.hypersistence.utils.hibernate.type.MutableType.nullSafeGet(MutableType.java:100)
	at org.hibernate.type.internal.UserTypeSqlTypeAdapter$ValueExtractorImpl.extract(UserTypeSqlTypeAdapter.java:110)
	at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.readCurrentRowValues(JdbcValuesResultSetImpl.java:314)
	at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.advance(JdbcValuesResultSetImpl.java:293)
	at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.processNext(JdbcValuesResultSetImpl.java:134)
	at org.hibernate.sql.results.jdbc.internal.AbstractJdbcValues.next(AbstractJdbcValues.java:19)
	at org.hibernate.sql.results.internal.RowProcessingStateStandardImpl.next(RowProcessingStateStandardImpl.java:66)
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:184)
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33)
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:361)
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
	at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
	at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:146)
	at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:118)
	at org.hibernate.loader.ast.internal.SingleIdEntityLoaderStandardImpl.load(SingleIdEntityLoaderStandardImpl.java:73)
	at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:3521)
	at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3511)
	at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:581)
	at org.hibernate.event.internal.DefaultLoadEventListener.loadFromCacheOrDatasource(DefaultLoadEventListener.java:567)
	at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:536)
	at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:529)
	at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:202)
	at org.hibernate.event.internal.DefaultLoadEventListener.loadWithRegularProxy(DefaultLoadEventListener.java:282)
	at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:237)
	at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:106)
	at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:78)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138)
	at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1231)
	at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1219)
	at org.hibernate.loader.internal.IdentifierLoadAccessImpl.doLoad(IdentifierLoadAccessImpl.java:201)
	at org.hibernate.loader.internal.IdentifierLoadAccessImpl.lambda$load$1(IdentifierLoadAccessImpl.java:160)
	at org.hibernate.loader.internal.IdentifierLoadAccessImpl.perform(IdentifierLoadAccessImpl.java:107)
	at org.hibernate.loader.internal.IdentifierLoadAccessImpl.load(IdentifierLoadAccessImpl.java:160)
	at org.hibernate.internal.SessionImpl.find(SessionImpl.java:2406)
	at org.hibernate.internal.SessionImpl.find(SessionImpl.java:2377)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360)
	at jdk.proxy2/jdk.proxy2.$Proxy181.find(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311)
	at jdk.proxy2/jdk.proxy2.$Proxy181.find(Unknown Source)
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:313)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:288)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516)
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:72)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:164)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)

I followed linked issues and tried to play with my mapper which looks like this:

@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
    return new Jackson2ObjectMapperBuilder()
            .modules(new Jdk8Module(), new JavaTimeModule())
            //.featuresToEnable(MapperFeature.REQUIRE_TYPE_ID_FOR_SUBTYPES) I tried enabling and disabling this but it doesn't change anything
            .serializationInclusion(JsonInclude.Include.NON_NULL)
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}

I must admit I'm no expert with all these libraries and settings and this code is not mine but I can definitely confirm that this is breaking. Is there any official documentation that I could follow to fix this breaking change and maybe use the "new way of doing things"?
Thanks a lot and sorry for polluting this PR but I think it might be helpful for other in my situation that end up here.

@JooHyukKim
Copy link
Member Author

JooHyukKim commented Dec 8, 2023

@JFCote the described issue does not relate to this issue. The error is because jackson modules were upgraded partiallly.

  • Make sure all Jackson modules have same minor version that is all should be 2.16. Probably jackson-annotation module is not 2.16, but 2.15 (not only jackson-annotation and others)
  • Check https://github.com/FasterXML/jackson-bom for more detail

@JFCote
Copy link

JFCote commented Dec 8, 2023

Thanks @JooHyukKim ! In fact, I was not importing jackson-annotation explicitly. It was probably imported by another dependencies using an old version. Forcing it to 2.16.0 did the trick!

@JooHyukKim
Copy link
Member Author

Yeah, transitive dependency problem is real 🙉. Glad it helped!

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

Successfully merging this pull request may close these issues.

None yet

3 participants