Skip to content

CaseClassMappingException occurs during the deserialization of query parameters. #593

@pipi-olo

Description

@pipi-olo

Describe the bug
com.twitter.util.jackson.caseclass.CaseClassDeserializer fails to properly deserialize the following case class.
case class TestRequest(@QueryParam names: Option[Seq[String]])

To Reproduce
Steps to reproduce the behavior:

import com.twitter.finatra.http.HttpServer
import com.twitter.finatra.http.routing.HttpRouter

object TestServerMain extends TestServer

class TestServer extends HttpServer {

  override protected def configureHttp(router: HttpRouter): Unit = router.add[TestController]
}
import com.twitter.finatra.http.Controller

class TestController extends Controller {

  get("/test") { request: TestRequest =>
    (request.age, request.names)
  }
}
import com.twitter.finatra.http.annotations.QueryParam

case class TestRequest(@QueryParam age: Int, @QueryParam names: Option[Seq[String]])

An exception occurs when you connect to http://localhost:8888/test?age=5&names=hello.

com.twitter.util.jackson.caseclass.exceptions.CaseClassMappingException: An error was encountered during deserialization.
	Error: com.twitter.util.jackson.caseclass.exceptions.CaseClassFieldMappingException: names: '' is not a valid Seq
	at com.twitter.util.jackson.caseclass.exceptions.CaseClassMappingException$.apply(CaseClassMappingException.scala:21)
	at com.twitter.util.jackson.caseclass.CaseClassDeserializer.deserialize(CaseClassDeserializer.scala:432)
	at com.twitter.util.jackson.caseclass.CaseClassDeserializer.deserializeNonWrapperClass(CaseClassDeserializer.scala:409)
	at com.twitter.util.jackson.caseclass.CaseClassDeserializer.deserialize(CaseClassDeserializer.scala:374)
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
	at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2105)
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1724)
	at com.twitter.finatra.http.marshalling.DefaultMessageBodyReaderImpl.parse(DefaultMessageBodyReaderImpl.scala:33)
	at com.twitter.finatra.http.marshalling.MessageBodyManager.read(MessageBodyManager.scala:338)
	at com.twitter.finatra.http.internal.routing.CallbackConverterImpl.$anonfun$createRequestCallback$4(CallbackConverter.scala:106)
	at com.twitter.finatra.http.internal.routing.CallbackConverterImpl.$anonfun$createResponseCallback$12(CallbackConverter.scala:170)
	at com.twitter.finagle.Service$$anon$2.apply(Service.scala:29)
	at com.twitter.finagle.Service$$anon$2.apply(Service.scala:28)
	at com.twitter.finatra.http.internal.routing.Route.handleMatch(Route.scala:76)
	at com.twitter.finatra.http.internal.routing.Routes.handle(Routes.scala:38)
	at com.twitter.finatra.http.internal.routing.RoutingService.route(RoutingService.scala:47)
	at com.twitter.finatra.http.internal.routing.RoutingService.apply(RoutingService.scala:36)
	at com.twitter.finatra.http.internal.routing.RoutingService.apply(RoutingService.scala:26)
	at com.twitter.finagle.ServiceProxy.apply(ServiceProxy.scala:12)
	at com.twitter.finagle.Service$$anon$1.apply(Service.scala:16)
	at com.twitter.finagle.tracing.AnnotatingTracingFilter.apply(TraceInitializerFilter.scala:177)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.tracing.ServerDestTracingFilter.apply(DestinationTracing.scala:56)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.filter.ExceptionSourceFilter.apply(ExceptionSourceFilter.scala:53)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.filter.MkJvmFilter$$anon$1.apply(MkJvmFilter.scala:30)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.http.filter.HttpTracingFilter$.apply(HttpTracingFilter.scala:16)
	at com.twitter.finagle.http.filter.HttpTracingFilter$.apply(HttpTracingFilter.scala:8)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.tracing.AnnotatingTracingFilter.apply(TraceInitializerFilter.scala:177)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.tracing.ResourceTracingFilter$ResourceUsageFilter$$anon$5.apply(TraceInitializerFilter.scala:277)
	at com.twitter.finagle.Filter$Adapter.apply(Filter.scala:237)
	at com.twitter.finagle.filter.FiberForkFilter.$anonfun$apply$1(FiberForkFilter.scala:35)
	at com.twitter.util.Fiber$.let(Fiber.scala:46)

        ...

Expected behavior
The "names" parameter should be properly mapped to the custom case class.

Screenshots
Image

Environment
I am using "com.twitter" %% "finatra-http-server" % "24.2.0" library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions