Option Module not working with Spring MVC 3.x #111

Closed
yairogen opened this Issue Nov 20, 2013 · 7 comments

Projects

None yet

2 participants

@yairogen

I have a spring mvc project. I created JacksonScalaHttpMessageConverter that extends Spring AbstractHttpMessageConverter. this is to make it work with case classes.

I have a case class with 2 options in the end:

case class Product(val productName: String, val productVersion: String, val accessPoints:Option[Collection[AccessPoint]], val foundationMachineId:Option[String], val foundationMachineIP:Option[String])

If I create instance of Instance case class that contains the above Product and pass None, None at the end - the serialization fails with:

com.fasterxml.jackson.databind.JsonMappingException: (None,None) (of class scala.Tuple2) (through reference chain: com.foo.Instance["product"]->com.cisco.vcs.foundation.scope.model.Product["foundationMachineId"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:197)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:186)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:640)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:541)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:632)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:114)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2811)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2234)

@christophercurrie
Member

I don't have enough information here to try and reproduce this. Can you provide the code for your Instance class, and how it's being created and serialized?

@yairogen

here are the case classes:

case class Product(val productName: String, val productVersion: String, val productOptions: Option[Array[ProductOption]], val accessPoints:Option[Collection[AccessPoint]], foundationMachineId:Option[String], foundationMachineIP:Option[String])

case class Instance (@(Id@field) val instanceId:String, val tenantId:String, val instanceName:String, val status:Option[String], val details:Option[String], val product: Product )

case class ProductOption(val key: String, val value: Option[String], val description: String, val optionType: String, defaultValue: String, enumeration: Option[Array[String]])

case class AccessPoint (val name:String, val url:String)

Initialization:

val accessPoints = new HashSet[AccessPoint]()
accessPoints.add(AccessPoint("foo","http://<host>:6040/foo"))
accessPoints.add(AccessPoint("bar","https://<host>:5015/bar/app.html"))
val newInst = Instance("528b584578db33eec95fc7f0","123456","myInstance 123",Some("STARTING"),None,Product("IM","1.23.4.7",None,Some(accessPoints),None,None))

Serialization:

val mapper = getMapper

def getMapper() = {
val module = new OptionModule with CaseClassModule {}
val mapper = new ObjectMapper()
mapper.registerModule(module)
mapper
}

when running:

println (mapper.writeValueAsString(newInst))

it works fine.

However, when using the following class to convert my INstance classs when it is passed as return type in a REST call it fails.

Here is the spring converter I wrote (it uses the same mapper definition as above):

import org.springframework.http.{ MediaType, HttpOutputMessage, HttpInputMessage }
import org.springframework.http.converter.AbstractHttpMessageConverter
import java.nio.charset.Charset

class JacksonScalaHttpMessageConverter extends AbstractHttpMessageConverter[Object](new MediaType%28"application",))) {

def writeInternal(t: Object, outputMessage: HttpOutputMessage) ={
mapper.writeValue(outputMessage.getBody,t)
}

def supports(clazz: Class[_]): Boolean = {
mapper.canSerialize(clazz) && mapper.canDeserialize(mapper.constructType(clazz))
}

def readInternal(clazz: Class[_ <: Object], inputMessage: HttpInputMessage): Object = {
mapper.readValue(inputMessage.getBody(),clazz)
}
}

@christophercurrie
Member

So, from your initial description, it seems to fail if you haven None in the last two arguments of Product? If you change the last two values of Product to Some("foo") and Some("bar"), does it start to work?

@yairogen

Oddly enough, when I try out your suggestion it still fails on the same error but on a different field (the 'details' Option):

com.fasterxml.jackson.databind.JsonMappingException: (None,None) (of class scala.Tuple2) (through reference chain: com.foo.Instance["details"])

changing this field from None to a Some - and everything is working fine.

Naturally - this is not our solution, right?

@christophercurrie
Member

No, but please pick up the thread on the user list, as it's easier to have a discussion there.

@christophercurrie
Member

Were you ever able to produce a failing test that is independent of MongoDB? If not, I'll assume at this point that MongoDB is the culprit and close the issue. Otherwise, feel free to pick up the thread on the mailing list.

@yairogen

You can close the issue.

I’ve migrated to Casbah and Salat. We’re good now.

Thanks for all your help.

From: Christopher Currie [mailto:notifications@github.com]
Sent: Friday, December 20, 2013 20:02
To: FasterXML/jackson-module-scala
Cc: Yair Ogen
Subject: Re: [jackson-module-scala] Option Module not working with Spring MVC 3.x (#111)

Were you ever able to produce a failing test that is independent of MongoDB? If not, I'll assume at this point that MongoDB is the culprit and close the issue. Otherwise, feel free to pick up the thread on the mailing list.


Reply to this email directly or view it on GitHub #111 (comment) . https://github.com/notifications/beacon/4748515__eyJzY29wZSI6Ik5ld3NpZXM6QmVhY29uIiwiZXhwaXJlcyI6MTcwMzA5NTI5NiwiZGF0YSI6eyJpZCI6MjA2MTM5MzJ9fQ==--50b3afe29ce0112ea0f7438643b0477535bc17d4.gif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment