简体   繁体   English

球衣/杰克逊中的Scala枚举序列化对我不起作用

[英]Scala enumeration serialization in jersey/jackson is not working for me

I've read the jackson-module-scala page on enumeration handling ( https://github.com/FasterXML/jackson-module-scala/wiki/Enumerations ). 我已经阅读了有关枚举处理的jackson-module-scala页面( https://github.com/FasterXML/jackson-module-scala/wiki/Enumerations )。 Still I'm not getting it to work. 我仍然无法正常工作。 The essential code goes like this: 基本代码如下所示:

@Path("/v1/admin")
@Produces(Array(MediaType.APPLICATION_JSON + ";charset=utf-8"))
@Consumes(Array(MediaType.APPLICATION_JSON + ";charset=utf-8"))
class RestService {

  @POST
  @Path("{type}/abort")
  def abortUpload(@PathParam("type") typeName: ResourceTypeHolder) {
    ...
  }
}

object ResourceType extends Enumeration {
    type ResourceType = Value
    val ssr, roadsegments, tmc, gab, tne = Value
}

class ResourceTypeType extends TypeReference[ResourceType.type]
case class ResourceTypeHolder(
  @JsonScalaEnumeration(classOf[ResourceTypeType])
  resourceType:ResourceType.ResourceType
)

This is how it's supposed to work, right? 这应该是这样工作的,对吗? Still I get these errors: 我仍然收到这些错误:

Following issues have been detected:
WARNING: No injection source found for a parameter of type public void no.tull.RestService.abortUpload(no.tull.ResourceTypeHolder) at index 0.

unavailable
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public void no.tull.RestService.abortUpload(no.tull.ResourceTypeHolder) at index 0.; source='ResourceMethod{httpMethod=POST, consumedTypes=[application/json; charset=utf-8], producedTypes=[application/json; charset=utf-8], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class no.tull.RestService, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@7ffe609f]}, definitionMethod=public void no.tull.RestService.abortUpload(no.tull.ResourceTypeHolder), parameters=[Parameter [type=class no.tull.ResourceTypeHolder, source=type, defaultValue=null]], responseType=void}, nameBindings=[]}']
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:467)
    at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:163)
    at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:323)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286)

I have also assembled a tiny runnable project (while trying to eliminate any other complications) that demonstrates the problem: project.tgz 我还组装了一个很小的可运行项目(同时尝试消除任何其他复杂性)来说明问题: project.tgz

Update: Created an sbt-file to see if gradle was building a strange build. 更新:创建了一个sbt文件来查看gradle是否正在构建一个奇怪的版本。 Got the same result, but this is the build.sbt : 得到了相同的结果,但这是build.sbt

name := "project"

version := "1.0"

scalaVersion := "2.10.4"

val jacksonVersion = "2.4.1"
val jerseyVersion = "2.13"

libraryDependencies ++= Seq(
  "com.fasterxml.jackson.core" % "jackson-annotations" % jacksonVersion,
  "com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion,
  "com.fasterxml.jackson.jaxrs" % "jackson-jaxrs-json-provider" % jacksonVersion,
  "com.fasterxml.jackson.jaxrs" % "jackson-jaxrs-base" % jacksonVersion,
  "com.fasterxml.jackson.module" % "jackson-module-scala_2.10" % jacksonVersion,
  "org.glassfish.jersey.containers" % "jersey-container-servlet-core" % jerseyVersion
)

seq(webSettings :_*)

libraryDependencies ++= Seq(
  "org.eclipse.jetty" % "jetty-webapp" % "9.1.0.v20131115" % "container",
  "org.eclipse.jetty" % "jetty-plus"   % "9.1.0.v20131115" % "container"
)

... and this is the project/plugins.sbt : ...这是project / plugins.sbt

addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.9.0")

You seem to possibly have a few problems with your tarball. 您的tarball似乎有一些问题。

You need to add some Scala modules to Jackson to be able to use any Scala functionality. 您需要向Jackson添加一些Scala模块,才能使用任何Scala功能。 That can be done by doing this: 可以这样做:

val jsonObjectMapper = new ObjectMapper()
jsonObjectMapper.registerModule(DefaultScalaModule)
val jsonProvider: JacksonJsonProvider = new JacksonJsonProvider(jsonObjectMapper)

According to this working jersey-jackson example . 根据这个工作中的泽克-杰克逊的例子 You also need to inject org.glassfish.jersey.jackson.JacksonFeature into Jersey which is found in jersey-media-json-jackson . 您还需要将org.glassfish.jersey.jackson.JacksonFeature注入到Jersey jersey-media-json-jackson找到的Jersey中。 My RestApplication.scala came out like this 我的RestApplication.scala像这样出来

import javax.ws.rs.core.Application
import javax.ws.rs.ext.{ContextResolver, Provider}

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.google.common.collect.ImmutableSet
import org.glassfish.jersey.jackson.JacksonFeature

@Provider
class ObjectMapperProvider extends ContextResolver[ObjectMapper] {
  val defaultObjectMapper = {
    val jsonObjectMapper = new ObjectMapper()
    jsonObjectMapper.registerModule(DefaultScalaModule)
    jsonObjectMapper
  }

  override def getContext(typ: Class[_]): ObjectMapper = {
    defaultObjectMapper
  }
}

class RestApplication extends Application {
  override def getSingletons: java.util.Set[AnyRef] = {
    ImmutableSet.of(
      new RestService,
      new ObjectMapperProvider,
      new JacksonFeature
    )
  }
}

The real issue, though, is the @PathParam annotation. 但是,真正的问题是@PathParam批注。 This code path doesn't invoke Jackson at all. 此代码路径根本不会调用Jackson。 However, what's interesting is that Jersey appears to generically support parsing to any type that has a constructor of a single string. 但是,有趣的是,Jersey似乎普遍支持解析为具有单个字符串的构造函数的任何类型。 So if you modify your ResourceTypeHolder you can get the functionality you want after all. 因此,如果您修改ResourceTypeHolder ,则毕竟可以获得所需的功能。

case class ResourceTypeHolder(@JsonScalaEnumeration(classOf[ResourceTypeType]) resourceType:ResourceType.ResourceType) {
  def this(name: String) = this(ResourceType.withName(name))
}

You might be able to add generic support for enum holders to Jersey as an injectable provider. 您也许可以将注射枚举支持者的枚举持有者的通用支持添加到Jersey。 However, that hasn't come up in dropwizard-scala, a project that would suffer the same fate as it uses Jersey too. 但是,dropwizard-scala并没有实现这一目标,该项目也将遭受与使用Jersey相同的命运。 Thus I imagine it's either impossible, or simply just not common enough for anyone to have done the work. 因此,我想这是不可能的,或者仅仅是对于任何人完成这项工作而言不够普遍。 When it comes to enum's, I tend to keep mine in Java. 当涉及到枚举时,我倾向于保留Java语言。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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