基于Jackson的版本依赖反序列化:未定义引用异常抛出问题
接口多实现类反序列化时的未定义引用异常问题
我需要根据JSON数据的version字段,将其反序列化为同一接口DatabaseI的不同实现类(Database1或Database2),目前通过自定义反序列化器已实现该功能。但我的数据结构中使用了对象引用(通过Jackson的@JsonIdentityInfo和@JsonIdentityReference注解实现),预期遇到未定义引用时抛出异常,但当前结合接口的实现方式无法触发该异常。
补充信息:若在readValue中直接使用具体类而非接口(例如用mapper.readValue(buggy, Database2.class);替代mapper.readValue(buggy, DatabaseI.class);),预期的异常抛出行为正常,但会失去对JSON具体内容的抽象能力。
以下是包含未通过测试用例的示例代码:
import static org.junit.jupiter.api.Assertions.assertThrows; import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.IntNode; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonIdentityReference; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; public class Example { @Test public void test() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); SimpleModule module = new SimpleModule(); module.addDeserializer(DatabaseI.class, new ToyDeserializer()); mapper.registerModule(module); String correct = "{'version':1,'people':[{'id':'a','friends':['b','c']},{'id':'b','friends':['c']},{'id':'c','friends':['b']}]}"; DatabaseI deserCorrect = mapper.readValue(correct, DatabaseI.class); System.out.println(mapper.writeValueAsString(deserCorrect)); String buggy = "{'version':2,'people':[{'id':'a','friends':['b','c']},{'id':'b','friends':['c']},{'id':'c','friends':['FOO']}]}"; assertThrows(Exception.class, () -> { mapper.readValue(buggy, DatabaseI.class); }, "The reference FOO is undefined. An Exception should be thrown."); } } class Person { @JsonProperty("id") private String id; @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @JsonIdentityReference(alwaysAsId = true) private List<Person> friends = new ArrayList<>(); public Person() { } public String getId() { return id; } public void setId(String id) { this.id = id; } public List<Person> getFriends() { return friends; } public void setFriends(List<Person> friends) { this.friends = friends; } } interface DatabaseI { } class Database1 implements DatabaseI { private int version; private List<Person> people = new ArrayList<>(); public Database1() { } public List<Person> getPeople() { return people; } public void setPeople(List<Person> people) { this.people = people; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } } class Database2 implements DatabaseI { private String version; private List<Person> people = new ArrayList<>(); public Database2() { } public List<Person> getPeople() { return people; } public void setPeople(List<Person> people) { this.people = people; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } } class ToyDeserializer extends StdDeserializer<DatabaseI> { protected ToyDeserializer(Class<?> vc) { super(vc); } public ToyDeserializer() { this(null); } @Override public DatabaseI deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException { ObjectMapper mapper = (ObjectMapper) jp.getCodec(); JsonNode node = mapper.readTree(jp); int version = (Integer) ((IntNode) node.get("version")).numberValue(); if (version == 1) { return mapper.treeToValue(node, Database1.class); } else { return mapper.treeToValue(node, Database2.class); } } }
内容的提问来源于stack exchange,提问作者heinrich
相关产品推荐
相关产品推荐

