Mru*_*ukh 4 json scala jackson deserialization
我有一个JSON,其形式如下:
{
"inventory": [
{
"productType": "someProduct1",
"details": {
"productId": "Some_id",
"description": "some description"
}
},
{
"productType": "someProduct2",
"details": {
"productId": "Some_id",
"description":{"someKey":"somevalue"}
}
}
]
}
Run Code Online (Sandbox Code Playgroud)
我希望上面的json反序列化的case类如下所示:
case class Inventory(products:List[Product])
case class Product(productType:String,details:ProductDetails)
abstract class ProductDetails
case class ProductDetailsSimple(productId:String,description:String) extends ProductDetails
case class ProductDetailsComplex(productId:String,description:Map[String,String]) extends ProductDetails
Run Code Online (Sandbox Code Playgroud)
我使用jackson-scala模块反序列化上面的JSON字符串,如下所示:
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
mapper.readValue(jsonBody, classOf[Inventory])
Run Code Online (Sandbox Code Playgroud)
我得到的错误如下:"意外令牌(END_OBJECT),期望FIELD_NAME:缺少属性'@details',包含类型ID(对于类ProductDetails)\n在[来源:java.io.StringReader@12dfbabd;行:9,专栏:5]"
我已经通过关于多态反序列化的杰克逊文档,并尝试了所提到的组合,但没有运气.我想了解我在这里做错了什么,需要使用jackson模块对反序列化进行修正.
And*_*w E 13
我认为这里有一些单独的问题要解决,所以我列出了三种不同的方法.
要么正确使用Jackson多态性,要么在您的情况下,采用更简单的方法并消除对多态性的需要.在github上查看我的代码.
您格式化的JSON是:
{ inventory:
[ { productType: 'someProduct1',
details:
{ productId: 'Some_id',
description: 'some description' } },
{ productType: 'someProduct2',
details:
{ productId: 'Some_id',
description: { someKey: 'somevalue' }
}
}
]
}
Run Code Online (Sandbox Code Playgroud)
productType在我看来,该字段是错误的,但如果这种格式是严格的要求,那么你可以编写自己的反序列productType化器来查看该字段并实例化一个不同的具体类.
我不认为这是最好的解决方案所以我没有编写示例代码,但我喜欢Joda日期时间包作为自定义序列化/反序列化的参考
你分离Product从ProductDetails利用类型字段:
case class Product(productType:String,details:ProductDetails)
abstract class ProductDetails
Run Code Online (Sandbox Code Playgroud)
我认为你已经混淆了Jackson的多态数据类型处理如何工作并因此使您的类设计复杂化.
也许您的业务规则要求产品具有"类型",在这种情况下,我将其命名为"kind"或其他非代码标签,并将其置于您所称的内容中ProductDetails.
但是,如果试图使类型多态性工作时包含"类型",那么它就不是正确的方法.
我在下面作为Scala中Jackson多态性的工作示例包含了以下内容:
/**
* The types here are close to the original question types but use
* Jackson annotations to mark the polymorphic JSON treatment.
*/
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])
Run Code Online (Sandbox Code Playgroud)
请注意,我删除了Productvs ProductDetails区别,所以Inventory现在只是作为列表Product.我留下了名字ProductDetailsSimple,ProductDetailsComplex虽然我认为他们应该重命名.
用法示例:
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)
Run Code Online (Sandbox Code Playgroud)
输出:
Polymorphic Inventory as JSON: {
"products" : [ {
"type" : "simple",
"productId" : "Some_id",
"description" : "some description"
}, {
"type" : "complex",
"productId" : "Some_id",
"description" : {
"someKey" : "somevalue"
}
} ]
}
Run Code Online (Sandbox Code Playgroud)
我建议在这种情况下根本不需要多态,并且错误在于尝试使"描述"成为单个字符串或键/值映射,而它们实际上是具有不同意图的字段.
也许涉及数据遗留问题(在这种情况下请参见自定义deser建议),但如果数据在您的控制范围内,我投票支持"go simpler":
case class Product(productId: String,
description: String="",
attributes: Map[String, String]=Map.empty)
case class PlainInventory(products: List[Product])
Run Code Online (Sandbox Code Playgroud)
我更用"scala-rific" Option来表示没有值,所以:
case class Product(productId: String,
description: Option[String]=None,
attributes: Option[Map[String, String]]=None)
Run Code Online (Sandbox Code Playgroud)
用法示例:
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)
Run Code Online (Sandbox Code Playgroud)
输出:
Plain Inventory as JSON: {
"products" : [ {
"productId" : "Some_id",
"description" : "some description"
}, {
"productId" : "Some_id",
"attributes" : {
"someKey" : "somevalue"
}
} ]
}
Run Code Online (Sandbox Code Playgroud)
在github上使用最少的代码.
| 归档时间: |
|
| 查看次数: |
8268 次 |
| 最近记录: |