I think there are several separate issues here, so I have listed three separate approaches.
TL DR
Make the right use of Jackson polymorphism or, in your case, move to a simpler approach and eliminate the need for polymorphism. See my code on github .
1. Custom deserializer
Your formatted JSON:
{ inventory: [ { productType: 'someProduct1', details: { productId: 'Some_id', description: 'some description' } }, { productType: 'someProduct2', details: { productId: 'Some_id', description: { someKey: 'somevalue' } } } ] }
The productType field productType inappropriate, in my opinion, but if this format is a strict requirement, you can write your own deserializer that looks in the productType field and creates an instance of another specific class.
I don’t think this would be a better solution, so I didn’t write the sample code, but I like the date-time of the Joda package as a reference for custom serialize / deserialize
2. Jackson Polymorphism
Separate Product from ProductDetails with a type field:
case class Product(productType:String,details:ProductDetails) abstract class ProductDetails
I think you are confused about how the processing of polymorphic data types in Jackson works, and as a result, the complex design of your class.
Perhaps your business rules require that the product has a “type”, in which case I would call it “good” or some other non-code, and put it in what you called ProductDetails .
But if "type" was included in an attempt to get typical polymorphism to work, then this is the wrong way.
I have included below as a working example of Jackson polymorphism in Scala:
import scala.Array import com.fasterxml.jackson.annotation.JsonSubTypes.Type import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo} @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes(Array( new Type(value = classOf[ProductDetailsSimple], name = "simple"), new Type(value = classOf[ProductDetailsComplex], name = "complex") )) abstract class Product case class ProductDetailsSimple(productId: String, description: String) extends Product case class ProductDetailsComplex(productId: String, description: Map[String, String]) extends Product case class PolymorphicInventory(products: List[Product])
Note that I removed the Product vs ProductDetails distinction, so Inventory now just like a Product list. I left the names ProductDetailsSimple and ProductDetailsComplex , although I think they should be renamed.
Usage example:
val inv = PolymorphicInventory( List( ProductDetailsSimple(productId="Some_id", description="some description"), ProductDetailsComplex(productId="Some_id", description=Map("someKey" -> "somevalue")) ) ) val s = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(inv) println("Polymorphic Inventory as JSON: "+s)
Output:
Polymorphic Inventory as JSON: { "products" : [ { "type" : "simple", "productId" : "Some_id", "description" : "some description" }, { "type" : "complex", "productId" : "Some_id", "description" : { "someKey" : "somevalue" } } ] }
3. Remove the polymorphism
I suggest that in this case polymorphism is not needed at all, and that the mistake is to try to make a “description” either as a single line or as a key / value map when they are really fields with different intentions.
Perhaps there is a problem of data obsolescence (in this case, see the hint for the user deserver), but if the data is under your control, I vote for "easier":
case class Product(productId: String, description: String="", attributes: Map[String, String]=Map.empty) case class PlainInventory(products: List[Product])
I more "scala -rific" use Option to indicate the absence of a value, therefore:
case class Product(productId: String, description: Option[String]=None, attributes: Option[Map[String, String]]=None)
Usage example:
val inv = PlainInventory( List( Product(productId="Some_id", description=Some("some description")), Product(productId="Some_id", attributes=Some(Map("someKey" -> "somevalue"))) ) ) val s = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(inv) println("Plain Inventory as JSON: "+s)
Output:
Plain Inventory as JSON: { "products" : [ { "productId" : "Some_id", "description" : "some description" }, { "productId" : "Some_id", "attributes" : { "someKey" : "somevalue" } } ] }
Working minimal code on github .