Java 使用 Jackson 将 JSON 反序列化为多态类型 - 一个完整的例子给了我一个编译错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30362446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deserialize JSON with Hymanson into Polymorphic Types - A Complete Example is giving me a compile error
提问by Jon Driscoll
I am attempting to work through a tutorial from Programmer Bruce that is supposed to allow the deserialization of polymorphic JSON.
我正在尝试完成程序员布鲁斯的教程,该教程应该允许对多态 JSON 进行反序列化。
The complete list can be found here Programmer Bruce tutorials(Great stuff btw)
完整列表可以在这里找到 程序员布鲁斯教程(顺便说一句,很棒的东西)
I have worked through the first five with no problems but I have hit a snag on the last one (Example 6), which of course is the one I really need to get working.
我已经完成了前五个没有问题,但我在最后一个(示例 6)上遇到了障碍,这当然是我真正需要开始工作的那个。
I am getting the following error at compile time
我在编译时收到以下错误
The method readValue(JsonParser, Class) in the type ObjectMapper is not applicable for the arguments (ObjectNode, Class)
ObjectMapper 类型中的 readValue(JsonParser, Class) 方法不适用于参数 (ObjectNode, Class)
and it's being caused by the chunk of code
它是由代码块引起的
public Animal deserialize(
JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
Class<? extends Animal> animalClass = null;
Iterator<Entry<String, JsonNode>> elementsIterator =
root.getFields();
while (elementsIterator.hasNext())
{
Entry<String, JsonNode> element=elementsIterator.next();
String name = element.getKey();
if (registry.containsKey(name))
{
animalClass = registry.get(name);
break;
}
}
if (animalClass == null) return null;
return mapper.readValue(root, animalClass);
}
}
Specifically by the line
具体按行
return mapper.readValue(root, animalClass);
返回 mapper.readValue(root,animalClass);
Has anyone run into this before and if so, was there a solution?
以前有没有人遇到过这个问题,如果有,有解决方案吗?
I'd appreciate any help anyone can give Thanks in advance Jon D.
我很感激任何人都可以提供的任何帮助提前致谢 Jon D.
采纳答案by jbarrueta
As promised, I'm putting an example for how to use annotations to serialize/deserialize polymorphic objects, I based this example in the Animal
class from the tutorial you were reading.
正如所承诺的,我正在举一个关于如何使用注释来序列化/反序列化多态对象的示例,我将这个示例基于Animal
您正在阅读的教程中的类。
First of all your Animal
class with the Json Annotations for the subclasses.
首先,您的Animal
类带有子类的 Json 注释。
import com.fasterxml.Hymanson.annotation.JsonIgnoreProperties;
import com.fasterxml.Hymanson.annotation.JsonSubTypes;
import com.fasterxml.Hymanson.annotation.JsonTypeInfo;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "Dog"),
@JsonSubTypes.Type(value = Cat.class, name = "Cat") }
)
public abstract class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then your subclasses, Dog
and Cat
.
然后是您的子类Dog
和Cat
.
public class Dog extends Animal {
private String breed;
public Dog() {
}
public Dog(String name, String breed) {
setName(name);
setBreed(breed);
}
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
}
public class Cat extends Animal {
public String getFavoriteToy() {
return favoriteToy;
}
public Cat() {}
public Cat(String name, String favoriteToy) {
setName(name);
setFavoriteToy(favoriteToy);
}
public void setFavoriteToy(String favoriteToy) {
this.favoriteToy = favoriteToy;
}
private String favoriteToy;
}
As you can see, there is nothing special for Cat
and Dog
, the only one that know about them is the abstract
class Animal
, so when deserializing, you'll target to Animal
and the ObjectMapper
will return the actual instance as you can see in the following test:
如您所见,Cat
and没有什么特别之处Dog
,唯一知道它们的是abstract
class Animal
,因此在反序列化时,您将定位到Animal
并且ObjectMapper
将返回实际实例,如您在以下测试中所见:
public class Test {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Animal myDog = new Dog("ruffus","english shepherd");
Animal myCat = new Cat("goya", "mice");
try {
String dogJson = objectMapper.writeValueAsString(myDog);
System.out.println(dogJson);
Animal deserializedDog = objectMapper.readValue(dogJson, Animal.class);
System.out.println("Deserialized dogJson Class: " + deserializedDog.getClass().getSimpleName());
String catJson = objectMapper.writeValueAsString(myCat);
Animal deseriliazedCat = objectMapper.readValue(catJson, Animal.class);
System.out.println("Deserialized catJson Class: " + deseriliazedCat.getClass().getSimpleName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output after running the Test
class:
运行Test
该类后的输出:
{"@type":"Dog","name":"ruffus","breed":"english shepherd"}
{"@type":"Dog","name":"ruffus","breed":"english shepherd"}
Deserialized dogJson Class: Dog
Deserialized dogJson Class: Dog
{"@type":"Cat","name":"goya","favoriteToy":"mice"}
{"@type":"Cat","name":"goya","favoriteToy":"mice"}
Deserialized catJson Class: Cat
Deserialized catJson Class: Cat
Hope this helps,
希望这可以帮助,
Jose Luis
何塞·路易斯
回答by ravi.zombie
If using the fasterxml then,
如果使用fasterxml然后,
these changes might be needed
可能需要进行这些更改
import com.fasterxml.Hymanson.core.JsonParser;
import com.fasterxml.Hymanson.core.JsonProcessingException;
import com.fasterxml.Hymanson.core.Version;
import com.fasterxml.Hymanson.databind.DeserializationContext;
import com.fasterxml.Hymanson.databind.JsonNode;
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.databind.deser.std.StdDeserializer;
import com.fasterxml.Hymanson.databind.module.SimpleModule;
import com.fasterxml.Hymanson.databind.node.ObjectNode;
in main method--
在主要方法中——
use
用
SimpleModule module =
new SimpleModule("PolymorphicAnimalDeserializerModule");
instead of
代替
new SimpleModule("PolymorphicAnimalDeserializerModule",
new Version(1, 0, 0, null));
and in Animal deserialize() function, make below changes
并在 Animal deserialize() 函数中,进行以下更改
//Iterator<Entry<String, JsonNode>> elementsIterator = root.getFields();
Iterator<Entry<String, JsonNode>> elementsIterator = root.fields();
//return mapper.readValue(root, animalClass);
return mapper.convertValue(root, animalClass);
This works for fasterxml.Hymanson. If it still complains of the class fields. Use the same format as in the json for the field names (with "_" -underscore). as this//mapper.setPropertyNamingStrategy(new CamelCaseNamingStrategy());
might not be supported.
这适用于fasterxml.Hymanson。如果它仍然抱怨类字段。对字段名称使用与 json 中相同的格式(带有“_”-下划线)。因为这//mapper.setPropertyNamingStrategy(new CamelCaseNamingStrategy());
可能不受支持。
abstract class Animal
{
public String name;
}
class Dog extends Animal
{
public String breed;
public String leash_color;
}
class Cat extends Animal
{
public String favorite_toy;
}
class Bird extends Animal
{
public String wing_span;
public String preferred_food;
}
回答by AmitW
A simple way to enable polymorphic serialization / deserialization via Hymanson library is to globally configure the Hymanson object mapper (Hymanson.databind.ObjectMapper) to add information, such as the concrete class type, for certain kinds of classes, such as abstract classes.
通过 Hymanson 库启用多态序列化/反序列化的一种简单方法是全局配置 Hymanson 对象映射器(Hymanson.databind.ObjectMapper),为某些类(例如抽象类)添加具体类类型等信息。
To do that, just make sure your mapper is configured correctly. For example:
为此,只需确保您的映射器配置正确。例如:
Option 1: Support polymorphic serialization / deserialization for abstract classes (and Object typed classes)
选项 1:支持抽象类(和对象类型类)的多态序列化/反序列化
HymansonObjectMapper.enableDefaultTyping(
ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
Option 2: Support polymorphic serialization / deserialization for abstract classes (and Object typed classes), and arrays of those types.
选项 2:支持抽象类(和对象类型类)和这些类型的数组的多态序列化/反序列化。
HymansonObjectMapper.enableDefaultTyping(
ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS);
Reference: https://github.com/FasterXML/Hymanson-docs/wiki/HymansonPolymorphicDeserialization
参考:https: //github.com/FasterXML/Hymanson-docs/wiki/HymansonPolymorphicDeserialization
回答by Marco
You need only one line before the declaration of the class Animal
for correct polymorphic serialization/deserialization:
您只需要在类声明前一行就可以Animal
进行正确的多态序列化/反序列化:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public abstract class Animal {
...
}
This line means: add a meta-property on serialization or read a meta-property on deserialization (include = JsonTypeInfo.As.PROPERTY
) called "@class" (property = "@class"
) that holds the fully-qualified Java class name (use = JsonTypeInfo.Id.CLASS
).
此行表示:在序列化时添加元属性或在反序列化时读取元属性 ( include = JsonTypeInfo.As.PROPERTY
),称为“@class”( property = "@class"
),其中包含完全限定的 Java 类名 ( use = JsonTypeInfo.Id.CLASS
)。
So, if you create a JSON directly (without serialization) remember to add the meta-property "@class" with the desired class name for correct deserialization.
因此,如果您直接创建 JSON(不进行序列化),请记住添加具有所需类名的元属性“@class”以进行正确的反序列化。
More information here
更多信息在这里