0
我的JSON是這樣的:動態傑克遜自定義解串器
{"typeName":"test","field":{"name":"42"}}
我有兩個解串器。第一個(JsonDeserializer<EntityImpl>
)將檢查JSON並提取由typeName
屬性提供的類型信息。
第二個解串器(JsonDeserializer<TestField>
)用於反序列化field
屬性。這個解串器需要知道之前提取的typeName
值才能正常工作。
我該如何將類型信息從一個反序列化器傳遞到其他反序列化器?我試圖用DeserializationContext但我不知道如何相處的背景下,從解串器的傳球到B
我當前的代碼如下所示:
EntityImpl.java:
package de.jotschi.test;
public class EntityImpl implements Entity {
private String typeName;
private TestField field;
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public TestField getField() {
return field;
}
public void setField(TestField field) {
this.field = field;
}
}
TestField的.java:
package de.jotschi.test;
public class TestField {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
測試:
package de.jotschi.test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import de.jotschi.test.EntityImpl;
import de.jotschi.test.TestField;
public class TestMapper2 {
private InjectableValues getInjectableValue() {
InjectableValues values = new InjectableValues() {
@Override
public Object findInjectableValue(Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance) {
if ("data".equals(valueId.toString())) {
return new HashMap<String, String>();
}
return null;
}
};
return values;
}
@Test
public void testMapper() throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule idAsRefModule = new SimpleModule("ID-to-ref", new Version(1, 0, 0, null));
idAsRefModule.addDeserializer(EntityImpl.class, new JsonDeserializer<EntityImpl>() {
@Override
public EntityImpl deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Map<String, String> dataMap = (Map) ctxt.findInjectableValue("data", null, null);
System.out.println("Value: " + dataMap.get("test"));
ObjectCodec codec = jp.getCodec();
JsonNode node = codec.readTree(jp);
String type = node.get("typeName").asText();
dataMap.put("typeName", type);
// How to pass on type information to TestField deserializer? The context is not reused for the next deserializer.
// I assume that readValueAs fails since the codec.readTree method has already been invoked.
//return jp.readValueAs(EntityImpl.class);
// Alternatively the treeToValue method can be invoked in combination with the node. Unfortunately all information about the DeserializationContext is lost. I assume new context will be created.
// How to reuse the old context?
return codec.treeToValue(node, EntityImpl.class);
}
});
idAsRefModule.addDeserializer(TestField.class, new JsonDeserializer<TestField>() {
@Override
public TestField deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// Access type from context
Map<String, String> dataMap = (Map) ctxt.findInjectableValue("data", null, null);
System.out.println(dataMap.get("typeName"));
ObjectCodec codec = p.getCodec();
JsonNode node = codec.readTree(p);
return codec.treeToValue(node, TestField.class);
}
});
mapper.registerModule(idAsRefModule);
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// Setup the pojo
EntityImpl impl = new EntityImpl();
impl.setTypeName("test");
TestField testField = new TestField();
testField.setName("42");
impl.setField(testField);
// POJO -> JSON
String json = mapper.writeValueAsString(impl);
System.out.println(json);
// JSON -> POJO
Entity obj = mapper.reader(getInjectableValue()).forType(EntityImpl.class).readValue(json);
System.out.println(obj.getClass().getName());
}
}
這種類型的信息手工處理重新確立的輪子。傑克遜已經可以做到了。看到這篇文章http://www.cowtowncoder.com/blog/archives/2010/03/entry_372.html – AdamSkywalker
我的類型信息不是指一個類。類型信息基本上用於在TestField derserializer內動態構建POJO。因此我不能使用傑克遜的類型系統。 – Jotschi