简体   繁体   中英

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

Update: Created an sbt-file to see if gradle was building a strange build. Got the same result, but this is the 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 :

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

You seem to possibly have a few problems with your tarball.

You need to add some Scala modules to Jackson to be able to use any Scala functionality. 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 . My RestApplication.scala came out like this

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. This code path doesn't invoke Jackson at all. However, what's interesting is that Jersey appears to generically support parsing to any type that has a constructor of a single string. So if you modify your ResourceTypeHolder you can get the functionality you want after all.

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. However, that hasn't come up in dropwizard-scala, a project that would suffer the same fate as it uses Jersey too. 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.

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