java - 使用 Jackson 从 JAXB 生成的 XML 反序列化 Map
问题描述
我需要反序列化一些使用 JAXB 生成的 XML。由于某些合规性问题,我只能使用 Jackson 进行 XML 解析。尝试反序列化具有 Map 的类时,我遇到了异常
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
at [Source: (StringReader); line: 40, column: 21] (through reference chain: FileConfig["otherConfigs"]->java.util.LinkedHashMap["entry"])
我的代码如下:
XML 文件:
. . .
<fileConfig>
<whetherNotify>false</whetherNotify>
<url>....some location....</url>
<includes>app.log</includes>
<fileType>...some string...</fileType>
<otherConfigs>
<entry>
<key>pathType</key>
<value>1</value>
</entry>
</otherConfigs>
</fileConfig>
. . .
文件配置.java
public class FileConfig implements Serializable {
protected Boolean whetherNotify = false;
protected String url;
protected String includes;
protected FileType fileType;
private Map<String, String> otherConfigs = new HashMap<String, String>();
....getters and setters.....
}
主.java
public class Main {
.
.
.
.
private static <T> T unmarshallFromXML(String xml, Class<T> parseToClass) throws IOException {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
xmlMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
xmlMapper.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
xmlMapper.setDefaultUseWrapper(false);
xmlMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
T parsedObject = xmlMapper.readValue(xml, parseToClass);
return parsedObject;
}
}
请建议一种使用 Jackson 成功解析该地图的方法。
解决方案
默认情况下Map
被序列化为XML
:
...
<key>value</key>
<key1>value1</key1>
...
格式。没有entry
元素。你有两个选择:
- 更改模型而不是
Map
使用List<Entry>
类型。 - 为类型实现自定义反序列化器
Map
。
新模式
您需要创建Entry
类:
class Entry {
private String key;
private String value;
// getters, setters, toString
}
并将FileConfig
类中的属性更改为:
List<Entry> otherConfigs;
自定义地图反序列化器
请参见下面的示例:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class XmlApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./test.xml");
XmlMapper xmlMapper = new XmlMapper();
FileConfig fileConfig = xmlMapper.readValue(xmlFile, FileConfig.class);
System.out.println(fileConfig);
}
}
class MapEntryDeserializer extends JsonDeserializer<Map<String, String>> {
@Override
public Map<String, String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Map<String, String> map = new HashMap<>();
JsonToken token;
while ((token = p.nextToken()) != null) {
if (token == JsonToken.FIELD_NAME) {
if (p.getCurrentName().equals("entry")) {
p.nextToken();
JsonNode node = p.readValueAsTree();
map.put(node.get("key").asText(), node.get("value").asText());
}
}
}
return map;
}
}
class FileConfig {
protected Boolean whetherNotify = false;
protected String url;
protected String includes;
@JsonDeserialize(using = MapEntryDeserializer.class)
private Map<String, String> otherConfigs;
// getters, setters, toString
}
上面的代码打印:
FileConfig{whetherNotify=false, url='....some location....', includes='app.log', otherConfigs={pathType1=2, pathType=1}}
推荐阅读
- python-3.x - 在 Matplotlib 中绘制“无”值
- python-2.7 - 如何减少语义相似的词?
- tensorflow - TensorFlow 数据集 api
- sql - 从 MSSQL 中的表中删除旧条目
- javascript - 在表单中添加输入字段、文本区域、下拉菜单,同时您可以修改/编辑表单
- python-3.x - 从源代码构建 TensorFlow 后,看到 __longjmp_chk: symbol not found 错误
- javascript - 仅从 html ajax 结果中附加选定的类
- python - Converting generator from read_sql in pandas to dataframe has failed
- android - Display markers in maps on android in the region that is displayed to me on my screen
- reactjs - TypeScript complains on my setState statement that is using property accessors