因为您无法更改 POJO 模型,您需要手动实现自定义反序列化器和处理类型。自定义反序列化器可能如下所示:
class AnimalJsonDeserializer extends JsonDeserializer<Animal> {
private Map<String, Class> availableTypes = new HashMap<>();
public AnimalJsonDeserializer() {
availableTypes.put("cat", Cat.class);
availableTypes.put("dog", Dog.class);
}
@Override
public Animal deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
ObjectNode root = parser.readValueAsTree();
JsonNode type = getProperty(parser, root, "type");
Animal<Object> animal = new Animal<>();
animal.setType(type.asText());
Class<?> pojoClass = availableTypes.get(animal.getType());
if (pojoClass == null) {
throw new JsonMappingException(parser, "Class is not found for " + animal.getType());
}
JsonNode details = getProperty(parser, root, "details");
animal.setDetails(parser.getCodec().treeToValue(details, pojoClass));
return animal;
}
private JsonNode getProperty(JsonParser parser, ObjectNode root, String property) throws JsonMappingException {
JsonNode value = root.get(property);
if (value.isMissingNode() || value.isNull()) {
throw new JsonMappingException(parser, "No " + property + " field!");
}
return value;
}
}
我们需要使用SimpleModule 类并为Animal 类注册反序列化器。示例用法:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
SimpleModule animalModule = new SimpleModule();
animalModule.addDeserializer(Animal.class, new AnimalJsonDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(animalModule);
Animal<Dog> dog = new Animal<>();
dog.setType("dog");
dog.setDetails(new Dog("Marley", true));
Animal<Cat> cat = new Animal<>();
cat.setType("cat");
cat.setDetails(new Cat("Tom", false));
Animal<Dog> husky = new Animal<>();
husky.setType("husky");
husky.setDetails(new Dog("Sib", true));
for (Animal animal : new Animal[]{dog, cat, husky}) {
String json = mapper.writeValueAsString(animal);
System.out.println("JSON: " + json);
System.out.println("Deserialized: " + mapper.readValue(json, Animal.class));
System.out.println();
}
}
}
上面的代码打印:
JSON: {"type":"dog","details":{"name":"Marley","goodBoy":true}}
Deserialized: Animal{type='dog', details=Dog{name='Marley', goodBoy=true}}
JSON: {"type":"cat","details":{"name":"Tom","naughty":false}}
Deserialized: Animal{type='cat', details=Cat{name='Tom', naughty=false}}
JSON: {"type":"husky","details":{"name":"Sib","goodBoy":true}}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Class is not found for husky
at [Source: (String)"{"type":"husky","details":{"name":"Sib","goodBoy":true}}"; line: 1, column: 56]
at AnimalJsonDeserializer.deserialize(JsonApp.java:69)
at AnimalJsonDeserializer.deserialize(JsonApp.java:50)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
at com.celoxity.JsonApp.main(JsonApp.java:44)
如果您可以更改课程,则可以使用 MixIn 功能。
如果您不能更改源类,您可以随时使用Mix-in 功能,该功能允许使用类似方法创建新接口并适当地注释所有必需的类。在您的情况下,我们还需要删除 type 属性,该属性将由 Jackson 自动处理。您的示例在更改后可能如下所示:
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Animal.class, AnimalMixIn.class);
Animal<Dog> dog = new Animal<>();
dog.setDetails(new Dog("Marley", true));
String dogJson = mapper.writeValueAsString(dog);
System.out.println(dogJson);
Animal dogDeserialized = mapper.readValue(dogJson, Animal.class);
System.out.println(dogDeserialized);
}
}
interface AnimalMixIn {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", include = JsonTypeInfo.As.EXTERNAL_PROPERTY)
@JsonSubTypes(value = {
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")})
Object getDetails();
}
class Animal<T> {
private T details;
public T getDetails() {
return details;
}
public void setDetails(T details) {
this.details = details;
}
@Override
public String toString() {
return "Animal{details=" + details + '}';
}
}
Cat 和 Dogs 类保持不变。以上代码打印:
{"details":{"name":"Marley","goodBoy":true},"type":"dog"}
Animal{details=Dog{name='Marley', goodBoy=true}}
另见: