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

ScalaObjectMapper#readValue fails when there's one of the fields is a case class nested in an object in 2.13.0-rc2 #542

Closed
mosesn opened this issue Sep 14, 2021 · 12 comments

Comments

@mosesn
Copy link

mosesn commented Sep 14, 2021

I haven't had a chance to try a simple reproduction case in my repl yet, but my suspicion is that this would fail:

// NOTE: This is actually fine, I was wrong.  I'm leaving the mistaken repro case so the thread makes sense.  See below for the actual repro

object Foo {
  object Bar {
    final case class Baz(num: Int)
  }
}

val mapper: ScalaObjectMapper = 
mapper.readValue[Foo.Bar.Baz]("""{"num": "3"}""")

EDIT: Here's an actual repro:

scala> :paste
// Entering paste mode (ctrl-D to finish)

import com.fasterxml.jackson.module.scala.ScalaObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.json.JsonMapper
val objectMapper = (JsonMapper.builder().addModule(DefaultScalaModule).build() :: ScalaObjectMapper)
object Foo { case class Bar(num: Int) }
class Baz(baz: Foo.Bar)
objectMapper.readValue[Qux]("""{"baz": {"num": "3"}}""")

// Exiting paste mode, now interpreting.

java.lang.InternalError: Malformed class name
  at java.lang.Class.getSimpleName(Class.java:1330)
  at java.lang.Class.getCanonicalName(Class.java:1399)
  at com.fasterxml.jackson.module.scala.util.TastyUtil$.hasTastyFile(TastyUtil.scala:10)
  at com.fasterxml.jackson.module.scala.util.ClassW.extendsScalaClass(Classes.scala:12)
  at com.fasterxml.jackson.module.scala.util.ClassW.extendsScalaClass$(Classes.scala:9)
  at com.fasterxml.jackson.module.scala.util.ClassW$$anon$1.extendsScalaClass(Classes.scala:34)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.isMaybeScalaBeanType(ScalaAnnotationIntrospectorModule.scala:200)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.isScala(ScalaAnnotationIntrospectorModule.scala:206)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.hasCreatorAnnotation(ScalaAnnotationIntrospectorModule.scala:63)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.findCreatorAnnotation(ScalaAnnotationIntrospectorModule.scala:86)
  at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findCreatorAnnotation(AnnotationIntrospectorPair.java:842)
  at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:650)
  at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:617)
  at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:426)
  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:642)
  at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4751)
  at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4621)
  at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3575)
  at com.fasterxml.jackson.module.scala.ScalaObjectMapper.readValue(ScalaObjectMapper.scala:206)
  at com.fasterxml.jackson.module.scala.ScalaObjectMapper.readValue$(ScalaObjectMapper.scala:205)
  at com.fasterxml.jackson.module.scala.ScalaObjectMapper$Mixin.readValue(ScalaObjectMapper.scala:14)
  ... 42 elided
```

Here's the stack trace I'm seeing:

```
                     java.lang.InternalError: Malformed class name
                     	at java.lang.Class.getSimpleName(Class.java:1330)
                     	at java.lang.Class.getCanonicalName(Class.java:1399)
                     	at com.fasterxml.jackson.module.scala.util.TastyUtil$.hasTastyFile(TastyUtil.scala:10)
                     	at com.fasterxml.jackson.module.scala.util.ClassW.extendsScalaClass(Classes.scala:12)
                     	at com.fasterxml.jackson.module.scala.util.ClassW.extendsScalaClass$(Classes.scala:9)
                     	at com.fasterxml.jackson.module.scala.util.ClassW$$anon$1.extendsScalaClass(Classes.scala:34)
                     	at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$._descriptorFor(ScalaAnnotationIntrospectorModule.scala:157)
                     	at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.fieldName(ScalaAnnotationIntrospectorModule.scala:173)
                     	at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.findImplicitPropertyName(ScalaAnnotationIntrospectorModule.scala:46)
                     	at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findImplicitPropertyName(AnnotationIntrospectorPair.java:502)
                     	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:632)
                     	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.findContextualValueDeserializer(DeserializationContext.java:609)
                     	at com.fasterxml.jackson.databind.deser.std.MapDeserializer.createContextual(MapDeserializer.java:316)
                     	at com.fasterxml.jackson.module.scala.deser.GenericMapFactoryDeserializerResolver$Deserializer.createContextual(GenericMapFactoryDeserializerResolver.scala:122)
                     	at com.fasterxml.jackson.databind.DeserializationContext.handlePrimaryContextualization(DeserializationContext.java:825)
                     	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:550)
                     	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:642)
                     	at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4751)
                     	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4621)
                     	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3575)
                     	at com.fasterxml.jackson.module.scala.ScalaObjectMapper.readValue(ScalaObjectMapper.scala:206)
                     	at com.fasterxml.jackson.module.scala.ScalaObjectMapper.readValue$(ScalaObjectMapper.scala:205)
```
@pjfanning
Copy link
Member

ScalaObjectMapper is deprecated - so it is not a high priority for maintenance. If you want to try a fix, please feel free to submit one.

pjfanning added a commit that referenced this issue Sep 14, 2021
@pjfanning
Copy link
Member

I just added b75861c - it passes for me using Scala 2.13.6 and Zulu JDK 11.0.10 - let's see how it fares on the CI/CD build.

@pjfanning
Copy link
Member

Seems similar to issue in scala/bug#2034 - maybe you could check a newer JDK to see if that helps

@mosesn
Copy link
Author

mosesn commented Sep 15, 2021

OK, I had time to actually sit down with a repl. It's trickier than I thought–the problem is when the case class is a field. It also doesn't need to be double nested.

Here's a repro:

scala> :paste
// Entering paste mode (ctrl-D to finish)

import com.fasterxml.jackson.module.scala.ScalaObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.json.JsonMapper
val objectMapper = (JsonMapper.builder().addModule(DefaultScalaModule).build() :: ScalaObjectMapper)
object Foo { case class Baz(num: Int) }
class Qux(qux: Foo.Baz)
objectMapper.readValue[Qux]("""{"qux": {"num": "3"}}""")

// Exiting paste mode, now interpreting.

java.lang.InternalError: Malformed class name
  at java.lang.Class.getSimpleName(Class.java:1330)
  at java.lang.Class.getCanonicalName(Class.java:1399)
  at com.fasterxml.jackson.module.scala.util.TastyUtil$.hasTastyFile(TastyUtil.scala:10)
  at com.fasterxml.jackson.module.scala.util.ClassW.extendsScalaClass(Classes.scala:12)
  at com.fasterxml.jackson.module.scala.util.ClassW.extendsScalaClass$(Classes.scala:9)
  at com.fasterxml.jackson.module.scala.util.ClassW$$anon$1.extendsScalaClass(Classes.scala:34)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.isMaybeScalaBeanType(ScalaAnnotationIntrospectorModule.scala:200)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.isScala(ScalaAnnotationIntrospectorModule.scala:206)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.hasCreatorAnnotation(ScalaAnnotationIntrospectorModule.scala:63)
  at com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector$.findCreatorAnnotation(ScalaAnnotationIntrospectorModule.scala:86)
  at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findCreatorAnnotation(AnnotationIntrospectorPair.java:842)
  at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:650)
  at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:617)
  at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:426)
  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:642)
  at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4751)
  at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4621)
  at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3575)
  at com.fasterxml.jackson.module.scala.ScalaObjectMapper.readValue(ScalaObjectMapper.scala:206)
  at com.fasterxml.jackson.module.scala.ScalaObjectMapper.readValue$(ScalaObjectMapper.scala:205)
  at com.fasterxml.jackson.module.scala.ScalaObjectMapper$Mixin.readValue(ScalaObjectMapper.scala:14)
  ... 42 elided

@mosesn mosesn changed the title ScalaObjectMapper#readValue fails on final case classes defined in doubly nested objects in 2.13.0-rc2 ScalaObjectMapper#readValue fails when there's one of the fields is a case class nested in an object in 2.13.0-rc2 Sep 15, 2021
@mosesn
Copy link
Author

mosesn commented Sep 15, 2021

ScalaObjectMapper is deprecated - so it is not a high priority for maintenance. If you want to try a fix, please feel free to submit one.

I understand, and I'm planning on migrating my company to ClassTagExtensions. However, we were unable to upgrade to 2.12.x because of a bug, so 2.13.x is our first version that has ClassTagExtensions. We would rather upgrade the version, and then switch to ClassTagExtensions as a separate commit, so that if we run into issues, we can tell whether they come from ClassTagExtensions. Would you mind continuing to support ScalaObjectMapper (at least as far as fixing regressions) for scala 2.12.x / 2.13.x for at least a little while until we are able to migrate?

@mosesn
Copy link
Author

mosesn commented Sep 15, 2021

OK, I tried repro-ing in JDK11, you're right that it's fixed if you do that. However, we will be unable to upgrade to JDK11 anytime soon (it's a work in progress). Can you use an API that's more JDK8-friendly in the meantime?

@pjfanning
Copy link
Member

pjfanning commented Sep 15, 2021

this test passes in our CI build on Java 8 - so it could be just a matter of using a more up to data Java 8 install or a different one - https://github.com/FasterXML/jackson-module-scala/runs/3604199825 ran using adopt open jdk 1.8

pjfanning added a commit that referenced this issue Sep 15, 2021
@pjfanning
Copy link
Member

pjfanning commented Sep 15, 2021

TastyUtil is a new class but Class.getCanonicalName (where this issue occurs) is used in 4 other places in the legacy jackson-module-scala code base - if this was a widespread issue, I would expect there to be lots of people complaining

mosesn added a commit to mosesn/jackson-module-scala that referenced this issue Sep 15, 2021
@mosesn
Copy link
Author

mosesn commented Sep 15, 2021

@pjfanning I was able to get a consistently failing reproduction case. It seems to fail across 2.11.x, 2.12.x, and 2.13.x.

mosesn@947e7f2

@pjfanning
Copy link
Member

pjfanning commented Sep 15, 2021

Looks like it is failing now in this PR - #543 - I've hacked a potential fix

@mosesn
Copy link
Author

mosesn commented Sep 16, 2021

Thank you!! I'll try a snapshot build tomorrow.

@mosesn
Copy link
Author

mosesn commented Sep 16, 2021

It worked, thank you again!

@mosesn mosesn closed this as completed Sep 16, 2021
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

2 participants