我正在寻找一种方法,以在List
项中进行反序列化,而无需在Jackson中使用注释。这可能吗?我到目前为止正在做的是尝试用一个<item>
标签替换一个告诉该物品类别的标签,但无济于事。即使这行得通,我也不确定杰克逊是否会提供一种处理该标签信息的方法。
为了更好地说明我的目标,下面是一个示例:
public class JacksonTest {
private static class ListElement {
private boolean value;
// getters, setters, constructors omitted
}
@Test
public void testDeSerialization() throws Exception {
final List<ListElement> existing = Arrays.asList(new ListElement(true));
final ObjectMapper mapper = new XmlMapper();
final JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, ListElement.class);
final String listString = mapper.writerFor(listJavaType).writeValueAsString(existing);
System.out.println(listString);
// "<List><item><value>true</value></item></List>"
}
}
因此,结果是<List><item><value>true</value></item></List>
,而我希望将<item>
标记替换为(限定的)类名称或提供type
属性。
当然,如果杰克逊无法处理此类名称,即使这样做也无济于事。
我在这里已经走到了尽头还是有路要走? p>
答案 0 :(得分:1)
您可以定义自己的JsonSerializer(也用于XML)并将其添加到JacksonXmlModule。
ToXmlGenerator具有setNextName函数,该函数可让您覆盖默认项目名称
private class MyListSerializer extends JsonSerializer<List> {
@Override
public void serialize(List list, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
for (Object obj : list) {
if (jsonGenerator instanceof ToXmlGenerator) {
ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
String className = obj.getClass().getSimpleName();
xmlGenerator.setNextName(new QName(className));
}
jsonGenerator.writeObject(obj);
// this is overridden at the next iteration
// and ignored at the last
jsonGenerator.writeFieldName("dummy");
}
}
@Override
public Class<List> handledType() {
return List.class;
}
}
@Test
public void testDeSerialization() throws Exception {
final List<ListElement> existing = Arrays.asList(new ListElement(true));
JacksonXmlModule module = new JacksonXmlModule();
module.addSerializer(new MyListSerializer());
final ObjectMapper mapper = new XmlMapper(module);
final JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, ListElement.class);
final ObjectWriter writer = mapper.writerFor(listJavaType);
final String listString = writer.writeValueAsString(existing);
System.out.println(listString);
// "<List><ListElement><value>true</value></ListElement></List>"
}
答案 1 :(得分:0)
好的,在对Evertude的建议进行了一些修补和调试之后,我找到了解决方案。我对序列化部分不是很满意,说实话,我不知道为什么要这样做。调试时,我注意到XmlGenerator::setNextName
必须被调用一次,但对下一次调用没有任何影响,因此我不得不在那里进行切换,并直接为循环中的下一项设置字段名
如果有人知道我在做什么错,我会很高兴,但至少我的尝试现在正在起作用:
@Test
public void testDeSerialization() throws Exception {
final List<ListElement> existing = Arrays.asList(new ListElement(true), new ListElement(false));
JacksonXmlModule module = new JacksonXmlModule();
module.addSerializer(new MyListSerializer());
final ObjectMapper mapper = new XmlMapper(module);
final JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, ListElement.class);
final ObjectWriter writer = mapper.writerFor(listJavaType);
final String listString = writer.writeValueAsString(existing);
module.addDeserializer(List.class, new MyListDeserializer());
List<ListElement> deserialized = mapper.readValue(listString, List.class);
assertEquals(existing, deserialized); // provided there're proper hash() and equals() methods
}
private class MyListSerializer extends JsonSerializer<List> {
@Override
public void serialize(List list, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
boolean done = false;
for (Object obj : list) {
if (jsonGenerator instanceof ToXmlGenerator) {
ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
String className = obj.getClass().getSimpleName();
// weird switch
if (!done) xmlGenerator.setNextName(new QName(className));
else jsonGenerator.writeFieldName(className);
done = true;
}
jsonGenerator.writeObject(obj);
}
}
@Override
public Class<List> handledType() {
return List.class;
}
}
private class MyListDeserializer extends JsonDeserializer<List> {
@Override
public List deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
List<Object> items = new ArrayList<>();
JsonToken nextToken;
while ((nextToken = p.nextToken()) != JsonToken.END_OBJECT) {
String currentName = p.currentName();
try {
String className = "my.test.project.JacksonCustomSerializer$" + currentName;
Class<?> loadClass = getClass().getClassLoader() // TODO put qualifier in ctxt?
.loadClass(className);
p.nextToken();
items.add(p.readValueAs(loadClass));
} catch (ClassNotFoundException e) {
// some handling
}
}
return items;
}
@Override
public Class<List> handledType() {
return List.class;
}
}