Jackson scala模块:serialize Enumeration失败

时间:2013-04-08 19:56:05

标签: json scala playframework-2.0 jackson

有人可以解释一下为什么这不起作用? 我和杰克逊一起使用Scala模块。

我的依赖是"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.1.3"

我的序列化器是:

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)
  }

}

没什么好看的,我只是将Scala模块添加到默认的序列化程序+ MongoDB ObjectId类的一些序列化程序。


这是我的简单测试代码:

@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
        )
      )
    )

这会产生输出:

{"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

因此只有第3次序列化失败。

我的枚举是基本的:

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

任何想法??? 我没有在我的枚举中定义任何类型的别名,为什么会出现这个错误?为什么在第3次尝试而不是在第2次具有相同的枚举?

顺便说一句,是否有可能:

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

而不是:

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

1 个答案:

答案 0 :(得分:1)

您有两个不同的问题:

  1. 为什么这段代码会抛出异常?

    我不知道,除了说scalabeans,杰克逊Scala模块的2.1系列所依赖的库,看起来它在Enumerations上有问题,可能特别是在Scala 2.10下。我会在related github issue

  2. 中跟踪此缺陷
  3. 枚举是否可以在序列化时不必传达其类型?

    还没有。详细说明为何relevant github issue;要点是因为Enumerations的Value类型只是类型别名而不是类型,所以每个Enumeration派生类的每个值在Java擦除下都具有相同的运行时类型。