Try searching on Stackoverflow, keyword might be "type id resolver"
On Wednesday, May 22, 2024 at 3:13:21 PM UTC+9 Chuanwise Rafter wrote: > So how to deserialize them gracefully with the help of Jackson? > > On Wednesday, May 22, 2024 at 12:39:42 PM UTC+8 Tatu Saloranta wrote: > >> On Tue, May 21, 2024 at 9:23 PM Chuanwise Rafter <rafte...@gmail.com> >> wrote: >> > >> > I need to deserialize incoming packet encoded in JSON. For example, >> there are two kind of packet: Son and Daughter. The rules are: >> > >> > If field "type" is not "sub", error occurred. >> > If field "type" is "sub", checking field "sub_type": >> > >> > if it's "son", deserialize it as `Son`. >> > if it's "daughter", deserialize it as `Daughter`. >> >> This is not a supported use case: Type Id can only come from a single >> property currently. >> It won't work even if you tried using different @JsonTypeInfo in >> subtypes -- it won't work as you might expect. >> >> -+ Tatu +- >> >> > >> > According to JacksonDocs - JacksonPolymorphicDeserialization, I add >> annotations @JsonTypeInfo and @JsonSubTypes: >> > >> > ```kotlin >> > import com.fasterxml.jackson.annotation.JsonSubTypes >> > import com.fasterxml.jackson.annotation.JsonTypeInfo >> > import >> com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy >> > import com.fasterxml.jackson.databind.annotation.JsonNaming >> > import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper >> > import com.fasterxml.jackson.module.kotlin.readValue >> > import org.junit.jupiter.api.Test >> > >> > @JsonTypeInfo( >> > use = JsonTypeInfo.Id.NAME, >> > property = "type", >> > include = JsonTypeInfo.As.PROPERTY, >> > visible = true >> > ) >> > @JsonSubTypes( >> > JsonSubTypes.Type(Sub::class, name = "sub"), >> > ) >> > @JsonNaming(SnakeCaseStrategy::class) >> > interface Base { >> > } >> > >> > @JsonTypeInfo( >> > use = JsonTypeInfo.Id.NAME, >> > property = "sub_type", >> > include = JsonTypeInfo.As.PROPERTY, >> > visible = true >> > ) >> > @JsonSubTypes( >> > JsonSubTypes.Type(Son::class, name = "son"), >> > JsonSubTypes.Type(Daughter::class, name = "daughter") >> > ) >> > interface Sub : Base { >> > } >> > >> > data class Son( >> > val sonField: String >> > ) : Sub >> > >> > data class Daughter( >> > val daughterField: String >> > ) : Sub >> > >> > class EventDataTest { >> > private val objectMapper = jacksonObjectMapper() >> > >> > @Test >> > fun testDeserializeBase() { >> > val json = """ >> > { >> > "type": "sub", >> > "sub_type": "son", >> > "son_field": "son" >> > } >> > """.trimIndent() >> > val base = objectMapper.readValue<Base>(json) >> > } >> > } >> > ``` >> > >> > But exception thrown: >> > >> > ``` >> > com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot >> construct instance of `cn.chuanwise.onebot.lib.v11.data.event.Sub` (no >> Creators, like default constructor, exist): abstract types either need to >> be mapped to concrete types, have custom deserializer, or contain >> additional type information >> > at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` >> disabled); line: 2, column: 11] >> > at >> com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) >> >> >> > at >> com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1887) >> >> >> > at >> com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:414) >> >> >> > at >> com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1375) >> >> >> > at >> com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:274) >> >> >> > at >> com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:170) >> >> >> > at >> com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:136) >> >> >> > at >> com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:263) >> >> >> > at >> com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74) >> >> >> > at >> com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342) >> >> >> > at >> com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4905) >> >> >> > at >> com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3848) >> >> >> > at >> com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3831) >> >> >> > at >> cn.chuanwise.onebot.lib.v11.data.event.EventDataTest.testDeserializeBase(EventDataTest.kt:93) >> >> >> > 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.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727) >> >> >> > at >> org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) >> >> >> > at >> org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) >> >> >> > at >> org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) >> >> >> > at >> org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) >> >> >> > at >> org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) >> >> >> > at >> org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) >> >> >> > at >> org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) >> >> >> > at >> org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) >> >> >> > at >> org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) >> >> >> > at >> org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) >> >> >> > at >> org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) >> >> >> > at >> org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) >> >> >> > at >> org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) >> >> >> > at >> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213) >> >> >> > at >> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138) >> >> >> > at >> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) >> >> >> > at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) >> > at >> org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) >> >> >> > at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) >> > at >> org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) >> >> >> > at >> org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) >> >> >> > at >> org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) >> >> >> > at >> org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) >> >> >> > at >> org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) >> >> >> > at >> org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) >> >> >> > at >> org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) >> >> >> > at >> org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) >> >> >> > at >> org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) >> >> >> > at >> org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) >> >> >> > at >> org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:110) >> >> >> > at >> org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:90) >> >> >> > at >> org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:85) >> >> >> > at >> org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62) >> >> >> > 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.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) >> >> >> > at >> org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) >> >> >> > at >> org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) >> >> >> > at >> org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) >> >> >> > at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source) >> > at >> org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193) >> >> >> > at >> org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129) >> >> >> > at >> org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) >> >> >> > at >> org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) >> >> >> > at >> org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) >> >> >> > at >> org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113) >> >> >> > at >> org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65) >> >> >> > at >> worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) >> >> >> > at >> worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) >> >> >> > ``` >> > >> > -- >> > You received this message because you are subscribed to the Google >> Groups "jackson-user" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> an email to jackson-user...@googlegroups.com. >> > To view this discussion on the web visit >> https://groups.google.com/d/msgid/jackson-user/089d7453-c8a5-405d-b96b-728c6556e103n%40googlegroups.com. >> >> >> > -- You received this message because you are subscribed to the Google Groups "jackson-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/jackson-user/e351c255-55b0-4788-99e9-f13413e14102n%40googlegroups.com.