简体   繁体   中英

Jackson scala module: serialize Enumeration fails

Can someone explain me why this doesn't work? I use the Scala module with Jackson.

My dependency is "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.1.3"

My serializer is:

import org.bson.types.ObjectId
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

object CustomSerializer {

  val objectMapper = new ObjectMapper()

  val module = new SimpleModule("CustomSerializer")
  module.addSerializer(classOf[Throwable], new ThrowableSerializer)
  module.addSerializer(classOf[ObjectId], new ObjectIdSerializer)
  module.addDeserializer(classOf[ObjectId], new ObjectIdDeserializer)
  val scalaModule = DefaultScalaModule

  objectMapper.registerModule(scalaModule)
  objectMapper.registerModule(module)

  def serialize(obj: AnyRef): String = {
    objectMapper.writeValueAsString(obj)
  }

}

Nothing really fancy, I just add the Scala module to the default serializer + some serializers for MongoDB ObjectId class.


Here's my simple test code:

@JsonIgnoreProperties(ignoreUnknown = true)
case class Relationship(
                         @Key("_id") id: ObjectId = new ObjectId,
                         fromUserId: ObjectId,
                         fromUserConfiguration: RelationshipConfiguration = new RelationshipConfiguration,
                         toUserId: ObjectId,
                         toUserConfiguration: RelationshipConfiguration = new RelationshipConfiguration,
                        status: RelationshipStatus.Value,
                         ) extends IdentifiableModel[Relationship] {

  ... some methods here
}

    case class SimpleCaseClass(string: String)
    case class SimpleCaseClassWithEnum(string: String,status: RelationshipStatus.Value)

    println(
      CustomSerializer.serialize( SimpleCaseClass("someString") )
    )
    println(
      CustomSerializer.serialize( SimpleCaseClassWithEnum("someString",RelationshipStatus.ACCEPTED) )
    )

    println(
      CustomSerializer.serialize(
        Relationship(
          fromUserId = new ObjectId("510f9398ed5080cb1265c8c2"),
          toUserId = new ObjectId("510f9398ed5080cb1265c8c2"),
          status = RelationshipStatus.ACCEPTED
        )
      )
    )

This produces the output:

{"string":"someString"}
{"string":"someString","status":{"enumClass":"models.RelationshipStatus","value":"ACCEPTED"}}
[21:35:58] ERROR application - 

! @6e03dp6pp - Internal server error, for (GET) [/me] ->

play.api.UnexpectedException: Unexpected exception[RuntimeException: Cannot resolve type alias Value in models.RelationshipStatus]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:142) ~[play_2.10.jar:2.1.0]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:106) ~[play_2.10.jar:2.1.0]
    at scala.Option.map(Option.scala:145) ~[scala-library.jar:na]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:106) ~[play_2.10.jar:2.1.0]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:104) ~[play_2.10.jar:2.1.0]
    at scala.util.Either$RightProjection.flatMap(Either.scala:523) [scala-library.jar:na]
    at play.core.ReloadableApplication.get(ApplicationProvider.scala:104) ~[play_2.10.jar:2.1.0]
    at play.core.server.Server$class.sendHandler$1(Server.scala:56) [play_2.10.jar:2.1.0]
    at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:88) [play_2.10.jar:2.1.0]
    at play.core.server.Server$$anonfun$getHandlerFor$4.apply(Server.scala:87) [play_2.10.jar:2.1.0]
    at scala.util.Either$RightProjection.flatMap(Either.scala:523) [scala-library.jar:na]
    at play.core.server.Server$class.getHandlerFor(Server.scala:87) [play_2.10.jar:2.1.0]
    at play.core.server.NettyServer.getHandlerFor(NettyServer.scala:34) [play_2.10.jar:2.1.0]
    at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:103) [play_2.10.jar:2.1.0]
    at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75) [netty.jar:na]
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565) [netty.jar:na]
    at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:793) [netty.jar:na]
    at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:104) [netty.jar:na]
    at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75) [netty.jar:na]
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565) [netty.jar:na]
    at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:793) [netty.jar:na]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) [netty.jar:na]
    at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:455) [netty.jar:na]
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:538) [netty.jar:na]
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:437) [netty.jar:na]
    at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75) [netty.jar:na]
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565) [netty.jar:na]
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:560) [netty.jar:na]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) [netty.jar:na]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) [netty.jar:na]
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:84) [netty.jar:na]
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:472) [netty.jar:na]
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:333) [netty.jar:na]
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:35) [netty.jar:na]
    at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102) [netty.jar:na]
    at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) [netty.jar:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) [na:1.7.0_01]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) [na:1.7.0_01]
    at java.lang.Thread.run(Thread.java:722) [na:1.7.0_01]
Caused by: java.lang.RuntimeException: Cannot resolve type alias Value in models.RelationshipStatus
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler.resolveTypeAlias(ScalaTypeCompiler.scala:202) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler.getTypeDecl$1(ScalaTypeCompiler.scala:159) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler.resolveScalaType(ScalaTypeCompiler.scala:167) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$3.apply(ScalaTypeCompiler.scala:146) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$3.apply(ScalaTypeCompiler.scala:145) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:na]
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:na]
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59) ~[scala-library.jar:na]
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47) ~[scala-library.jar:na]
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244) ~[scala-library.jar:na]
    at scala.collection.AbstractTraversable.map(Traversable.scala:105) ~[scala-library.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler.compile(ScalaTypeCompiler.scala:145) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1$$anonfun$apply$2.apply(ScalaTypeCompiler.scala:51) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1$$anonfun$apply$2.apply(ScalaTypeCompiler.scala:48) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at scala.Option$WithFilter.map(Option.scala:206) ~[scala-library.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1.apply(ScalaTypeCompiler.scala:48) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1.apply(ScalaTypeCompiler.scala:47) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at scala.Option.flatMap(Option.scala:170) ~[scala-library.jar:na]
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$.classInfoOf(ScalaTypeCompiler.scala:47) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4.apply(PropertyDescriptor.scala:225) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4.apply(PropertyDescriptor.scala:224) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at scala.Option.flatMap(Option.scala:170) ~[scala-library.jar:na]
    at org.scalastuff.scalabeans.PropertyDescriptor$.apply(PropertyDescriptor.scala:224) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.util.SmarterBeanIntrospector$.com$fasterxml$jackson$module$scala$util$SmarterBeanIntrospector$$createPropertyDescriptor$1(ScalaBeansUtil.scala:68) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.util.SmarterBeanIntrospector$$anonfun$5$$anonfun$apply$5.apply(ScalaBeansUtil.scala:103) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.util.SmarterBeanIntrospector$$anonfun$5$$anonfun$apply$5.apply(ScalaBeansUtil.scala:94) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:na]
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:na]
    at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33) ~[scala-library.jar:na]
    at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:105) ~[scala-library.jar:na]
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244) ~[scala-library.jar:na]
    at scala.collection.mutable.ArrayOps$ofRef.map(ArrayOps.scala:105) ~[scala-library.jar:na]
    at com.fasterxml.jackson.module.scala.util.SmarterBeanIntrospector$$anonfun$5.apply(ScalaBeansUtil.scala:94) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.util.SmarterBeanIntrospector$$anonfun$5.apply(ScalaBeansUtil.scala:93) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251) ~[scala-library.jar:na]
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251) ~[scala-library.jar:na]
    at scala.collection.immutable.List.foreach(List.scala:309) ~[scala-library.jar:na]
    at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251) ~[scala-library.jar:na]
    at scala.collection.AbstractTraversable.flatMap(Traversable.scala:105) ~[scala-library.jar:na]
    at com.fasterxml.jackson.module.scala.util.SmarterBeanIntrospector$.apply(ScalaBeansUtil.scala:93) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.util.ScalaBeansUtil$.propertiesOf(ScalaBeansUtil.scala:166) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.deser.CaseClassAnnotationIntrospector$.findConstructorParamName(CaseClassDeserializerModule.scala:51) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.module.scala.deser.CaseClassAnnotationIntrospector$.findDeserializationName(CaseClassDeserializerModule.scala:41) ~[jackson-module-scala_2.10-2.1.3.jar:na]
    at com.fasterxml.jackson.databind.AnnotationIntrospector.findNameForDeserialization(AnnotationIntrospector.java:915) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findNameForDeserialization(AnnotationIntrospectorPair.java:606) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:405) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:233) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:142) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:68) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:11) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.SerializationConfig.introspect(SerializationConfig.java:490) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:131) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.ser.SerializerFactory.createSerializer(SerializerFactory.java:53) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:935) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:892) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:429) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:520) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:99) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2627) ~[jackson-databind-2.1.2.jar:2.1.2]
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2119) ~[jackson-databind-2.1.2.jar:2.1.2]
    at utils.CustomSerializer$.serialize(CustomSerializer.scala:24) ~[na:na]
    at Global$.onStart(Global.scala:36) ~[na:na]
    at play.api.GlobalPlugin.onStart(GlobalSettings.scala:175) ~[play_2.10.jar:2.1.0]
    at play.api.Play$$anonfun$start$1$$anonfun$apply$mcV$sp$1.apply(Play.scala:63) ~[play_2.10.jar:2.1.0]
    at play.api.Play$$anonfun$start$1$$anonfun$apply$mcV$sp$1.apply(Play.scala:63) ~[play_2.10.jar:2.1.0]
    at scala.collection.immutable.List.foreach(List.scala:309) ~[scala-library.jar:na]
    at play.api.Play$$anonfun$start$1.apply$mcV$sp(Play.scala:63) ~[play_2.10.jar:2.1.0]
    at play.api.Play$$anonfun$start$1.apply(Play.scala:63) ~[play_2.10.jar:2.1.0]
    at play.api.Play$$anonfun$start$1.apply(Play.scala:63) ~[play_2.10.jar:2.1.0]
    at play.utils.Threads$.withContextClassLoader(Threads.scala:18) ~[play_2.10.jar:2.1.0]
    at play.api.Play$.start(Play.scala:62) ~[play_2.10.jar:2.1.0]
    at play.core.ReloadableApplication$$anonfun$get$1$$anonfun$1.apply(ApplicationProvider.scala:133) ~[play_2.10.jar:2.1.0]
    ... 38 common frames omitted

So only the 3rd serialization fail.

My Enumeration is basic:

object RelationshipStatus extends Enumeration {
  val PENDING = Value("PENDING")
  val ACCEPTED = Value("ACCEPTED")
  val REJECTED = Value("REJECTED")
  val IGNORED = Value("IGNORED")
}

Any idea??? I don't define any type alias in my Enumeration, so why this error? why on the 3rd attempt and not on the 2nd which has the same enum?

By the way, is it possible to have:

{"string":"someString","status":"ACCEPTED"}

Instead of:

{"string":"someString","status":{"enumClass":"models.RelationshipStatus","value":"ACCEPTED"}}

You have two different questions:

  1. Why is this code throwing an exception?

    I don't know, other than to say that scalabeans , a library that the 2.1 series of the Jackson Scala module depends, looks like it's having trouble with Enumerations, possibly specifically under Scala 2.10. I'll track this defect in the related github issue .

  2. Can Enumerations not have to convey their type when serialized?

    Not yet. Details why are in the relevant github issue ; the gist is that since the Value types for Enumerations are just type alias and not types, every value of every Enumeration-derived class has the same runtime type under Java erasure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM