FasterXML / jackson-module-scala

Add-on module for Jackson (https://github.com/FasterXML/jackson) to support Scala-specific datatypes
Apache License 2.0
501 stars 141 forks source link

fix 3.0.0-SNAPSHOT build issues #431

Closed pjfanning closed 3 years ago

pjfanning commented 5 years ago

Compilation fails due to major changes in jackson-databind

https://travis-ci.org/FasterXML/jackson-module-scala/jobs/588055923

pjfanning commented 3 years ago

Jackson 2 logging (with additional stacktaces) - the 2nd call never happens in Jackson 3.

So for some reason, jackson-databind neglects to get the scala class information for the MetricPath class. And then, jackson 3 is unable to deserialize any json for Metrics because it doesn't know how deserialize MetricPaths. For some reason, Jackson 3 does not properly analyse classes that are the types of object members.

java.lang.Exception: >>>> class com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest$Metric
  | => jat com.fasterxml.jackson.module.scala.introspect.BeanIntrospector$.apply(BeanIntrospector.scala:227)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$._descriptorFor(ScalaAnnotationIntrospectorModule.scala:154)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.fieldName(ScalaAnnotationIntrospectorModule.scala:165)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.findImplicitPropertyName(ScalaAnnotationIntrospectorModule.scala:46)
    at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findImplicitPropertyName(AnnotationIntrospectorPair.java:501)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:530)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:421)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:386)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:233)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._findCreatorsFromProperties(BasicDeserializerFactory.java:328)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:272)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:223)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:261)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:415)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:350)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:591)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4725)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4595)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3551)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3519)
    at com.fasterxml.jackson.module.scala.deser.DeserializerTest.deserialize(DeserializerTest.scala:18)
    at com.fasterxml.jackson.module.scala.deser.DeserializerTest.deserialize$(DeserializerTest.scala:17)
    at com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest.deserialize(CaseClassDeserializerTest.scala:61)
    at com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest.$anonfun$new$2(CaseClassDeserializerTest.scala:72)
    at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
    at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
    at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
    at org.scalatest.Transformer.apply(Transformer.scala:22)
    at org.scalatest.Transformer.apply(Transformer.scala:20)
    at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1684)
    at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
    at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
    at org.scalatest.flatspec.AnyFlatSpec.withFixture(AnyFlatSpec.scala:1685)
    at org.scalatest.flatspec.AnyFlatSpecLike.invokeWithFixture$1(AnyFlatSpecLike.scala:1682)
    at org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTest$1(AnyFlatSpecLike.scala:1694)
    at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1694)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1676)
    at org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1685)
    at org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1752)
    at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
    at scala.collection.immutable.List.foreach(List.scala:333)
    at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
    at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
    at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
    at scala.collection.immutable.List.foreach(List.scala:333)
    at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
    at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
    at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1752)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1751)
    at org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1685)
    at org.scalatest.Suite.run(Suite.scala:1112)
    at org.scalatest.Suite.run$(Suite.scala:1094)
    at org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1685)
    at org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1797)
    at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
    at org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1797)
    at org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1795)
    at org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1685)
    at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:318)
    at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:513)
    at sbt.TestRunner.runTest$1(TestFramework.scala:139)
    at sbt.TestRunner.run(TestFramework.scala:154)
    at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.$anonfun$apply$1(TestFramework.scala:317)
    at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:277)
    at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.apply(TestFramework.scala:317)
    at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.apply(TestFramework.scala:317)
    at sbt.TestFunction.apply(TestFramework.scala:329)
    at sbt.Tests$.$anonfun$toTask$1(Tests.scala:422)
    at sbt.std.Transform$$anon$3.$anonfun$apply$2(Transform.scala:46)
    at sbt.std.Transform$$anon$4.work(Transform.scala:68)
    at sbt.Execute.$anonfun$submit$2(Execute.scala:282)
    at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
    at sbt.Execute.work(Execute.scala:291)
    at sbt.Execute.$anonfun$submit$1(Execute.scala:282)
    at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
java.lang.Exception: >>>> class com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest$MetricPath
    at com.fasterxml.jackson.module.scala.introspect.BeanIntrospector$.apply(BeanIntrospector.scala:227)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$._descriptorFor(ScalaAnnotationIntrospectorModule.scala:154)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.fieldName(ScalaAnnotationIntrospectorModule.scala:165)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.findImplicitPropertyName(ScalaAnnotationIntrospectorModule.scala:46)
    at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findImplicitPropertyName(AnnotationIntrospectorPair.java:501)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:530)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:421)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:386)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:233)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164)
    at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._findCreatorsFromProperties(BasicDeserializerFactory.java:328)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:272)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:223)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:261)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:415)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:350)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findNonContextualValueDeserializer(DeserializationContext.java:581)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:539)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:294)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:591)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4725)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4595)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3551)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3519)
    at com.fasterxml.jackson.module.scala.deser.DeserializerTest.deserialize(DeserializerTest.scala:18)
    at com.fasterxml.jackson.module.scala.deser.DeserializerTest.deserialize$(DeserializerTest.scala:17)
    at com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest.deserialize(CaseClassDeserializerTest.scala:61)
    at com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest.$anonfun$new$2(CaseClassDeserializerTest.scala:72)
    at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
    at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
    at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
    at org.scalatest.Transformer.apply(Transformer.scala:22)
    at org.scalatest.Transformer.apply(Transformer.scala:20)
    at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1684)
    at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
    at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
    at org.scalatest.flatspec.AnyFlatSpec.withFixture(AnyFlatSpec.scala:1685)
    at org.scalatest.flatspec.AnyFlatSpecLike.invokeWithFixture$1(AnyFlatSpecLike.scala:1682)
    at org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTest$1(AnyFlatSpecLike.scala:1694)
    at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1694)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1676)
    at org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1685)
    at org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1752)
    at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
    at scala.collection.immutable.List.foreach(List.scala:333)
    at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
    at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
    at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
    at scala.collection.immutable.List.foreach(List.scala:333)
    at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
    at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
    at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1752)
    at org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1751)
    at org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1685)
    at org.scalatest.Suite.run(Suite.scala:1112)
    at org.scalatest.Suite.run$(Suite.scala:1094)
    at org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1685)
    at org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1797)
    at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
    at org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1797)
    at org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1795)
    at org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1685)
    at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:318)
    at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:513)
    at sbt.TestRunner.runTest$1(TestFramework.scala:139)
    at sbt.TestRunner.run(TestFramework.scala:154)
    at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.$anonfun$apply$1(TestFramework.scala:317)
    at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:277)
    at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.apply(TestFramework.scala:317)
    at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.apply(TestFramework.scala:317)
    at sbt.TestFunction.apply(TestFramework.scala:329)
    at sbt.Tests$.$anonfun$toTask$1(Tests.scala:422)
    at sbt.std.Transform$$anon$3.$anonfun$apply$2(Transform.scala:46)
    at sbt.std.Transform$$anon$4.work(Transform.scala:68)
    at sbt.Execute.$anonfun$submit$2(Execute.scala:282)
    at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
    at sbt.Execute.work(Execute.scala:291)
    at sbt.Execute.$anonfun$submit$1(Execute.scala:282)
    at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
pjfanning commented 3 years ago

Jackson 3 seems to do value instantiation first

java.lang.Exception: >>>> class com.fasterxml.jackson.module.scala.deser.CaseClassDeserializerTest$Metric
  | => cat com.fasterxml.jackson.module.scala.introspect.BeanIntrospector$.apply(BeanIntrospector.scala:227)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$._descriptorFor(ScalaAnnotationIntrospectorModule.scala:164)
    at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.findValueInstantiator(ScalaAnnotationIntrospectorModule.scala:149)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:172)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:255)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:393)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:330)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:225)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:146)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:637)
cowtowncoder commented 3 years ago

So the "missing" method would be findImplicitPropertyName()?

pjfanning commented 3 years ago

findImplicitPropertyName is implemented in the ScalaAnnotationIntrospector and gets call correctly for Metric but not for the MetricPath class. I've been trying to step though jackson-databind but the jackson-databind code is not something I really understand. I can see the jackson-databind code does look at the properties of Metric class including the property with MetricPath type but gives up and never calls findImplicitPropertyName for the MetricPath class.

Is it possible that jackson 3 requires ScalaAnnotationIntrospector to implement more methods? - right now it is only overrides a small number of methods on NopAnnotationIntrospector

cowtowncoder commented 3 years ago

Ok. It is possible other things might be needed. But another thing is that introspection may also be little bit asynchronous, in that order in which things go may be different. Perhaps debug statements in POJOPropertiesCollector could show if MetricPath even gets introspected.

pjfanning commented 3 years ago

POJOPropertiesCollector never gets instantiated for MetricPath (in jackson 3). It does for Metric class.

I'm debugging code in IntelliJ - it is easy to get IntelliJ to debug the jackson-module-scala tests - it's just that I simply do not understand the code in jackson-databind, so I do not know what to look for in order to explain why jackson 3 and not jackson 2 refuses to introspect the MetricPath class.

jackson-module-scala is unusable if it cannot handle classes like Metric.

cowtowncoder commented 3 years ago

@pjfanning Is there something special about MetricPath? I could try to troubleshoot this if I can somehow recreate the type... skipping of POJOPropertiesCollector would likely be due to either deserializer being created using some other mechanism (it's taken to be some other "well-known" type, like if if it was an Enum), or if it was not yet needed.

Too bad jackson-integration-tests is just for 2.x at this point. I wonder if it'd be worth creating 2.x branches and make master be for 3.0; that way it'd be slightly easier for me to debug some Scala cases. Unfortunately I haven't been able to (in the past at least) get jackson-module-scala (or, jackson-module-kotlin for that matter) to load up successfully on Eclipse. I sometimes use IntelliJ but on that my problem is that unlike with Eclipse I cannot actually get it to debug through local snapshot version for some reason (on Eclipse if I have snapshot version open it gets properly associated so I can get matching versions to run, add breakpoints etc).

pjfanning commented 3 years ago

There is nothing special about Metric - it is as plain a class as you could possibly have in Scala.

_createAndCache2 in DeserializerCache - this code in Jackson2 works perfectly -

            if (deser instanceof ResolvableDeserializer) {
                this._incompleteDeserializers.put(type, deser);
                ((ResolvableDeserializer)deser).resolve(ctxt);
                this._incompleteDeserializers.remove(type);
            }

The resolve on BeanDeserializerBase walks the object graph - picking up all the type information for the class and the classes of its members.

The new code in jackson 3 does not even try to read the class information for the classes of the members.

cowtowncoder commented 3 years ago

@pjfanning Right I would be surprised if resolution did not proceed. What I am trying to think of is where between locating a deserialization and introspection properties things get derailed. (delegation for Java beans works fine in that there are no failure cases there for 3.0)

What is the fail message again? Presumable a deserializer (but not functioning one) gets created or... ?

pjfanning commented 3 years ago

in jackson 3 BeanDeserializerFactory addBeanProps, the code just simply fails to get the creator property for the 'path' property that had MetricPath type

pjfanning commented 3 years ago

@cowtowncoder test fails with https://github.com/FasterXML/jackson-module-scala/issues/431#issuecomment-775584637

cowtowncoder commented 3 years ago

Ok, perhaps it'd be simpler to troubleshoot direct deserialization of MetricPath type: I assume that would fail as well but perhaps show direct stack trace (as opposed to indirect via Metric). I think I incorrectly referred to Metric earlier as well.

cowtowncoder commented 3 years ago

Oh, wait, perhaps not. If the inner type (MetricPath, right?) is passed as creator parameter of outer type (Metric), the lack of introspection of the inner type may be simply due to failure earlier. Until deserializer is assigned, all that is needed is type resolution (to get JavaType).

If so it would be due to missing linkage when resolving pieces of Metric and nothing to do with MetricPath -- deserializer for latter is not yet needed: it would be, at a later point, but deserializer building code is missing link between "regular" and Creator property for path (of Metric). That is a problem on its own but not showing an issue with introspection.

At least if I am understanding the situation better now.

pjfanning commented 3 years ago

MetricPath deserializes ok if it is deserialized by itself - the issue is when it is the type of a member of another class.

cowtowncoder commented 3 years ago

Ok that makes sense. The problem seems to be that introspection does not find creator property for some reason. Not MetricPath type itself. In fact it would seem that it could as well be any other type (String) and same should occur?

At this point, would it make sense to create a new issue for this one problem. Not sure if there are other ones, but discussion here has gotten bit long and covers a few different issues, most resolved?

pjfanning commented 3 years ago

I found some code in the Scala annotation classes that is not behaving as it does in Jackson 2 - let me investigate this - it could be the cause of the issue here

pjfanning commented 3 years ago

@cowtowncoder a possible/probable cause is that the jackson-module-scala was modified in jackson 3 because the interface in jackson-databind changed.

ValueInstantiators findValueInstantiator(DeserializationConfig var1, BeanDescription var2, ValueInstantiator var3) has dropped the final param - the defaultValueInstantiator

The scala code now struggles to replace that default. Any suggestions as to how to get a default instantiator in jackson 3?

cowtowncoder commented 3 years ago

@pjfanning Let me see, I think this was just split in two parts or so.

Ok, yes; so, there is new modifyValueInstantiator() which is what you want to use in case you want to use the default one: so existing findValueInstantiator() is meant for full override case; and then modifyValueInstantiator() for things like delegation.

pjfanning commented 3 years ago

I have no value instantiator so can't modify it. Is there any way to create a new default instantiator that has all the creator properties calculated - that's what I get in jackson 2 - automatically but now I am left with no instantiator and need to create from scratch .

findValueInstantiator(config: DeserializationConfig, ...) -- because this method does not give access to a full DeserializationContext, it is hard to try BeanDeserializerBuilder to try to get a value instantiator from it

cowtowncoder commented 3 years ago

Please look at signature:

    default ValueInstantiator modifyValueInstantiator(DeserializationConfig config,
            BeanDescription beanDesc, ValueInstantiator defaultInstantiator);

you are given the default instantiator UNLESS earlier call to

    public ValueInstantiator findValueInstantiator(DeserializationConfig config,
            BeanDescription beanDesc);

already returned a ValueInstantiator.

So basically earlier single call was split in two parts: one to ask for instantiator, and if none given, a default POJO instantiator is created and passed to give another chance for custom variants.

So if you want to use that default instantiator it is given and you may return it as-is, or create different one based on it (or just ignore).

pjfanning commented 3 years ago
    default ValueInstantiator modifyValueInstantiator(DeserializationConfig config,
            BeanDescription beanDesc, ValueInstantiator defaultInstantiator) {
        return defaultInstantiator;
    }

I have no defaultInstantiator to pass in

cowtowncoder commented 3 years ago

Ok now I am confused. This is a callback method of ValueInstantiators interface. Scala module should not usually be calling it.... it is called by Jackson databind (specifically BasicDeserializerFactory). Modules would implement ValueInstantiators callback to be able to provide alternative instantiator. That handling was split from 1 to 2 methods.

If Scala module does need to call it, where is the code? Maybe I can help with it.

pjfanning commented 3 years ago

In jackson 2, the perfect value instantiator is created in BasicDeserializer.findValueInstantiator -- and specifically when this is called instantiator = this._constructDefaultValueInstantiator(ctxt, beanDesc);

This instantiator is then used when the call to the old ValueInstantiators findValueInstantiator(DeserializationConfig var1, BeanDescription var2, ValueInstantiator var3) function is called

pjfanning commented 3 years ago

https://github.com/FasterXML/jackson-module-scala/blob/2.13/src/main/scala/com/fasterxml/jackson/module/scala/introspect/ScalaAnnotationIntrospectorModule.scala#L130

pjfanning commented 3 years ago

I think I fixed it - I made the findValueInstantiator return null so now the modifyValueInstantiator is called with the instantiator created in the BasicDeserializer

pjfanning commented 3 years ago

We're now down to 2 or 3 commented out tests in master that pass in jackson v2 and that fail in v3 - today's fix fixed about 5 broken tests

cowtowncoder commented 3 years ago

@pjfanning Ok good, yes, findValueInstantiator() should return null to indicate "go ahead construct default one" and then that one will be passed for possible modification/replacement. So fix makes sense.

Getting very close to parity which is good!

pjfanning commented 3 years ago

created https://github.com/FasterXML/jackson-module-scala/issues/536 for follow on work