为了账号安全,请及时绑定邮箱和手机立即绑定

基于属性值的杰克逊 XML 绑定元素

基于属性值的杰克逊 XML 绑定元素

狐的传说 2022-09-22 16:37:13

我有以下结构:XML


<participants>

    <participant side="AWAY">

        <team id="18591" name="Orlando Apollos" />

    </participant>

    <participant side="HOME">

        <team id="18594" name="Memphis Express" />

    </participant>

</participants>

如果我使用带有注释的库,如何将参与者字段绑定到两个不同的对象,并使用 和 的属性绑定字段。FasterXML JacksonJAXBParticipantparticipantHomeparticipantAwaysideAWAYHOME


使用以下对象显然不起作用,因为存在重复的字段:


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;

}

如何使用注释或自定义实现动态绑定这些元素?JAXBJAXB


查看完整描述

3 回答

?
慕哥9229398

TA贡献1548条经验 获得超5个赞

您需要编写自定义的去细节,因为没有注释允许将列表项绑定到 object 中的给定属性。如果已在使用,请尝试实现自定义 Json 序列化程序,而不是自定义 Xml适配器。我们可以通过将内部对象反序列化为 来简化我们的自定义去序列化器。简单示例:JacksonParticipantMap

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'}}



查看完整回答
反对 回复 4天前
?
守着一只汪

TA贡献1536条经验 获得超3个赞

您可以使用“参与者列表”代替两个不同的参与者。用@XmlAttribute注释(名称 = “side”,必需 = true)。然后创建两个不同的参与者对象并将其添加到列表中。


查看完整回答
反对 回复 4天前
?
月关宝盒

TA贡献1463条经验 获得超4个赞

这里有一些很棒的答案和替代方案,但我决定使用与列表绑定的混合,并通过实现返回正确的主队或客队的 getter 方法来返回正确的或团队,以基本上扁平化 .这将减少在整个应用程序中处理列表时的计算量。homeawayList


我将以下代码添加到我的父类(每个/参与者):homeaway


Participant getHome() {

    return (Participant) participants.stream()

            .filter(p -> p.getSide().equalsIgnoreCase("home"));

}


Participant getAway() {

    return (Participant) participants.stream()

            .filter(p -> p.getSide().equalsIgnoreCase("away"));

}

感谢您的帮助!


查看完整回答
反对 回复 4天前

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信