diff --git a/build.sbt b/build.sbt index 6b5abf00..2ad043d4 100644 --- a/build.sbt +++ b/build.sbt @@ -241,7 +241,9 @@ mimaBinaryIssueFilters ++= Seq( ProblemFilters.exclude[DirectMissingMethodProblem]("com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector.findSerializationKeyType"), ProblemFilters.exclude[DirectMissingMethodProblem]("com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector.findSerializationType"), ProblemFilters.exclude[DirectMissingMethodProblem]("com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector.findSerializationInclusionForContent"), - ProblemFilters.exclude[DirectMissingMethodProblem]("com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector.findSerializationInclusion") + ProblemFilters.exclude[DirectMissingMethodProblem]("com.fasterxml.jackson.module.scala.introspect.ScalaAnnotationIntrospector.findSerializationInclusion"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("com.fasterxml.jackson.module.scala.util.ClassW.getModuleField"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("com.fasterxml.jackson.module.scala.util.ClassW.com$fasterxml$jackson$module$scala$util$ClassW$$moduleField") ) def compareVersions(version1: String, version2: String): Int = { diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/ScalaObjectDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/ScalaObjectDeserializerModule.scala index fe061873..b6908df6 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/ScalaObjectDeserializerModule.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/ScalaObjectDeserializerModule.scala @@ -10,22 +10,15 @@ import com.fasterxml.jackson.module.scala.util.ClassW import scala.languageFeature.postfixOps import scala.util.control.NonFatal -private class ScalaObjectDeserializer(clazz: Class[_]) extends StdDeserializer[Any](classOf[Any]) { - override def deserialize(p: JsonParser, ctxt: DeserializationContext): Any = { - try { - clazz.getField("MODULE$").get(null) - } catch { - case NonFatal(_) => null - } - } +private class ScalaObjectDeserializer(value: Any) extends StdDeserializer[Any](classOf[Any]) { + override def deserialize(p: JsonParser, ctxt: DeserializationContext): Any = value } private object ScalaObjectDeserializerResolver extends Deserializers.Base { override def findBeanDeserializer(javaType: JavaType, config: DeserializationConfig, beanDesc: BeanDescription): JsonDeserializer[_] = { - val clazz = javaType.getRawClass - if (ClassW(clazz).isScalaObject) - new ScalaObjectDeserializer(clazz) - else null + ClassW(javaType.getRawClass).getModuleField.flatMap { field => + Option(field.get(null)) + }.map(new ScalaObjectDeserializer(_)).orNull } } diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospector.scala b/src/main/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospector.scala index ff77ce6b..92855ae7 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospector.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/introspect/BeanIntrospector.scala @@ -184,12 +184,11 @@ object BeanIntrospector { //create properties for all appropriate fields val fields = for { cls <- hierarchy - scalaCaseObject = isScalaCaseObject(cls) - isScalaObject = ClassW(cls).isScalaObject field <- cls.getDeclaredFields + isScalaObject = ClassW(cls).isScalaObject || isScalaCaseObject(cls) name = maybePrivateName(field) if !name.contains('$') - if (isScalaObject || scalaCaseObject || isAcceptableField(field)) + if isScalaObject || isAcceptableField(field) beanGetter = findBeanGetter(cls, name) beanSetter = findBeanSetter(cls, name) } yield PropertyDescriptor(name, findConstructorParam(hierarchy.head, name), Some(field), findGetter(cls, name), findSetter(cls, name), beanGetter, beanSetter) diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/util/Classes.scala b/src/main/scala/com/fasterxml/jackson/module/scala/util/Classes.scala index c0aaf2f7..3452de3d 100644 --- a/src/main/scala/com/fasterxml/jackson/module/scala/util/Classes.scala +++ b/src/main/scala/com/fasterxml/jackson/module/scala/util/Classes.scala @@ -1,5 +1,6 @@ package com.fasterxml.jackson.module.scala.util +import java.lang.reflect.Field import scala.annotation.tailrec import scala.language.implicitConversions import scala.reflect.{ScalaLongSignature, ScalaSignature} @@ -28,9 +29,11 @@ trait ClassW extends PimpedType[Class[_]] { hasSigHelper(value) } - def isScalaObject: Boolean = { - Try(value.getField("MODULE$")).isSuccess - } + def isScalaObject: Boolean = moduleField.isSuccess + + def getModuleField: Option[Field] = moduleField.toOption + + private lazy val moduleField: Try[Field] = Try(value.getField("MODULE$")) } object ClassW { diff --git a/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseObjectDeserializerTest.scala b/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseObjectDeserializerTest.scala index 9f65e681..b0c4cea3 100644 --- a/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseObjectDeserializerTest.scala +++ b/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseObjectDeserializerTest.scala @@ -22,7 +22,7 @@ class CaseObjectDeserializerTest extends DeserializerTest { val original = TestObject val json = mapper.writeValueAsString(original) val deserialized = mapper.readValue(json, TestObject.getClass) - assert(deserialized == original) + assert(deserialized === original) } it should "deserialize Foo and not create a new instance" in { @@ -30,7 +30,7 @@ class CaseObjectDeserializerTest extends DeserializerTest { val original = Foo val json = mapper.writeValueAsString(original) val deserialized = mapper.readValue(json, Foo.getClass) - assert(deserialized == original) + assert(deserialized === original) } it should "deserialize Foo and not create a new instance (visibility settings)" in { @@ -42,7 +42,7 @@ class CaseObjectDeserializerTest extends DeserializerTest { val original = Foo val json = mapper.writeValueAsString(original) val deserialized = mapper.readValue(json, Foo.getClass) - assert(deserialized == original) + assert(deserialized === original) } "An ObjectMapper with ClassTagExtensions and DefaultScalaModule" should "deserialize a case object and not create a new instance" in { @@ -52,7 +52,7 @@ class CaseObjectDeserializerTest extends DeserializerTest { val original = TestObject val json = mapper.writeValueAsString(original) val deserialized = mapper.readValue[TestObject.type](json) - assert(deserialized == original) + assert(deserialized === original) } "An ObjectMapper without ScalaObjectDeserializerModule" should "deserialize a case object but create a new instance" in {