使用Jackson将棘手的XML反序列化为POJO



Java 8, Spring 5.x

给定

ResponseEntity<Object> responnse = restTemplate.exchange( myUrl, HttpMethod.GET, reqquest, Object.class);

返回一些XML

<LinkedHashMap>
<Entity>
<name>Person</name>
<href>../12345</href>
<Attribute>
<name>lastName</name>
<type>String</type>
<value>Nixon</value>
</Attribute>
<Attribute>
<name>firstName</name>
<type>String</type>
<value>Dick</value>
</Attribute>
</Entity>
</LinkedHashMap>

@JsonIgnoreProperties(ignoreUnknown=true)
@JacksonXmlRootElement(localName="Person")
@Entity
public class Person implements java.io.Serializable {
private static final long serialVersionUID = 123456789L;
@Id
private Long id;
private String lastName;
private String firstName;
...
}

我如何调整这个

if( responnse.hasBody()){
Person person = xmlMapper.readValue( responnse.getBody(), Person.class);
...
}

我认为xmlMapper至少需要一些定制来处理id。

TIA,

苦苦挣扎的史蒂夫

我不知道是否有优雅和通用的解决方案,但是您可以创建自定义反序列化器,手动遍历XML并填充Person类:

class PersonDeserializer extends StdDeserializer<Person> {
protected PersonDeserializer() {
super(Person.class);
}
@Override
public Person deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Person result = new Person();
do {
String value = p.getText();
if (value.equals("Attribute")) {
p.nextToken(); // {
p.nextToken(); // name
p.nextToken(); // <attrName>
String propertyName = p.getText();
if (propertyName.equals("lastName")) {
p.nextToken(); // type
p.nextToken(); // String
p.nextToken(); // value
p.nextToken(); // <attrValue>
result.setLastName(p.getText());
} else if (propertyName.equals("firstName")) {
p.nextToken(); // type
p.nextToken(); // String
p.nextToken(); // value
p.nextToken(); // value=<attrProperty>
result.setFirstName(p.getText());
}
} else if (value.equals("href")) {
p.nextToken(); // value
String href = p.getText();
Long id = Long.parseLong(href.replaceAll("\D", "")); // "../12345" => "12345"
result.setId(id);
}
p.nextToken();
} while (p.hasCurrentToken());
return result;
}
}
然后像这样调用
XmlMapper mapper = new XmlMapper();
SimpleModule module = new SimpleModule("xmlPersonModule");
module.addDeserializer(Person.class, new PersonDeserializer());
mapper.registerModule(module);
String xml = """
<LinkedHashMap>
<Entity>
<name>Person</name>
<href>../12345</href>
<Attribute>
<name>lastName</name>
<type>String</type>
<value>Nixon</value>
</Attribute>
<Attribute>
<name>firstName</name>
<type>String</type>
<value>Dick</value>
</Attribute>
</Entity>
</LinkedHashMap>
""";
Person person = mapper.readValue(xml, Person.class);
System.out.println(person);

输出:

Person(id=12345, lastName=Nixon, firstName=Dick)

注:这是一个丑陋且不灵活的解决方案,当给定的XML结构发生变化时,它将失败,但是……它只是工作:)

最新更新