我有以下XML
结构:
<participants>
<participant side="AWAY">
<team id="18591" name="Orlando Apollos" />
</participant>
<participant side="HOME">
<team id="18594" name="Memphis Express" />
</participant>
</participants>
如果我使用带有FasterXML Jackson
注释的JAXB
库,我如何使用Participant
和participantHome
的participantAway
属性将参与者字段绑定到两个不同的side
对象AWAY
和HOME
来绑定字段。
使用以下对象显然不起作用,因为有重复的字段:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "participants")
public class Participants {
@XmlElement(name = "participant")
Participant participantHome;
@XmlElement(name = "participant")
Participant participantAway;
}
如何使用JAXB
注释或自定义JAXB
实现动态绑定这些元素?
您需要编写自定义反序列化器,因为没有注释允许将列表项绑定到对象中的给定属性。如果你已经使用Jackson
尝试实现自定义JsonDeserializer
而不是自定义XmlAdapter
。我们可以通过将内部Participant
对象反序列化为Map
来简化我们的自定义反序列化器。简单的例子:
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.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
XmlMapper xmlMapper = new XmlMapper();
Participants result = xmlMapper.readValue(xmlFile, Participants.class);
System.out.println(result);
}
}
class ParticipantsXmlAdapter extends JsonDeserializer<Participants> {
@Override
public Participants deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
List<Map<String, Object>> participants = readParticipantsMap(p, ctxt);
Participants result = new Participants();
for (Map<String, Object> participantMap : participants) {
Object side = participantMap.get("side").toString();
if ("AWAY".equals(side)) {
result.setParticipantAway(convert((Map<String, Object>) participantMap.get("team")));
} else if ("HOME".equals(side)) {
result.setParticipantHome(convert((Map<String, Object>) participantMap.get("team")));
}
}
return result;
}
private List<Map<String, Object>> readParticipantsMap(JsonParser p, DeserializationContext ctxt) throws IOException {
MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
JsonDeserializer<Object> mapDeserializer = ctxt.findRootValueDeserializer(mapType);
List<Map<String, Object>> participants = new ArrayList<>();
p.nextToken(); // skip Start of Participants object
while (p.currentToken() == JsonToken.FIELD_NAME) {
p.nextToken(); // skip start of Participant
Object participant = mapDeserializer.deserialize(p, ctxt);
participants.add((Map<String, Object>) participant);
p.nextToken(); // skip end of Participant
}
return participants;
}
private Participant convert(Map<String, Object> map) {
Participant participant = new Participant();
participant.setId(Integer.parseInt(map.get("id").toString()));
participant.setName(map.get("name").toString());
return participant;
}
}
@JsonDeserialize(using = ParticipantsXmlAdapter.class)
class Participants {
private Participant participantHome;
private Participant participantAway;
// getters, setters, toString
}
class Participant {
private int id;
private String name;
// getters, setters, toString
}
打印:
Participants{participantHome=Participant{id=18594, name='Memphis Express'}, participantAway=Participant{id=18591, name='Orlando Apollos'}}
您可以使用参与者列表代替两个不同的参与者。用@XmlAttribute注释一边(name =“side”,required = true)。然后创建两个不同的Participant对象并将它们添加到列表中。
这里有很多很棒的答案和替代品,但是我决定采用混合物与列表绑定并返回正确的home
或away
团队,通过实施getter方法返回正确的主场或客队以基本上压扁List
。这将减少整个应用程序中处理列表时的计算量。
我将以下代码添加到我的父类(每个home
/ away
参与者):
Participant getHome() {
return (Participant) participants.stream()
.filter(p -> p.getSide().equalsIgnoreCase("home"));
}
Participant getAway() {
return (Participant) participants.stream()
.filter(p -> p.getSide().equalsIgnoreCase("away"));
}
谢谢您的帮助!