Skip to content

CaseClassMappingException occurs during the deserialization of query parameters. #593

@mkyuhwan

Description

@mkyuhwan

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions