【问题标题】:JAXB serialized XML with ID references rather than containment带有 ID 引用而不是包含的 JAXB 序列化 XML
【发布时间】:2012-11-10 01:56:48
【问题描述】:

在 RestFul-Webservice (Jersey) 上下文中,我需要将对象图编组/序列化为 XML 和 JSON。为简单起见,我尝试用 2-3 个类来解释问题:

Person.java

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Person {

    private String name;

    // @XmlIDREF
    @XmlElement(name = "house")
    @XmlElementWrapper(name = "houses")
    private Collection<House> houses;

    public Person() {}

    public Person(String name, Collection<House> houses) {
        this.name = name;
        this.houses = houses;
    }
}

House.java

@XmlAccessorType(XmlAccessType.FIELD)
public class House {

    // @XmlID
    public String name;

    public String location;

    public House() {}

    public House(String name, String location) {
        this.name = name;
        this.location = location;
    }
}

现在当我序列化一个 Person 时,XML 将如下所示:

<people>
    <person>
        <name>Edward</name>
        <houses>
            <house>
                <name>MyAppartment</name>
                <location>London</location>
            </house>
            <house>
                <name>MySecondAppartment</name>
                <location>London</location>
            </house>
        </houses>
    </person>

    <person>
        <name>Thomas</name>
        <houses>
            <house>
                <name>MyAppartment</name>
                <location>London</location>
            </house>
            <house>
                <name>MySecondAppartment</name>
                <location>London</location>
            </house>
        </houses>
    </person>
</people>

这里的问题是,相同的房屋被多次列出。现在我添加未注释的 XmlIDREFXmlID 注释,这将导致 XML 类似于:

<people>
    <person>
        <name>Edward</name>
        <houses>
            <house>MyAppartment</house>
            <house>MySecondAppartment</house>
        </houses>
    </person>

    <person>
        <name>Thomas</name>
        <houses>
            <house>MyAppartment</house>
            <house>MySecondAppartment</house>
        </houses>
    </person>
</people>

虽然第一个 XML 过于冗长,但这个 XML 缺乏信息。如何创建(和解组)类似于:

<people>
    <person>
        <name>Edward</name>
        <houses>
            <house>MyAppartment</house>
            <house>MySecondAppartment</house>
        </houses>
    </person>

    <person>
        <name>Thomas</name>
        <houses>
            <house>MyAppartment</house>
            <house>MySecondAppartment</house>
        </houses>
    </person>

    <houses>
        <house>
            <name>MyAppartment</name>
            <location>London</location>
        </house>
        <house>
            <name>MySecondAppartment</name>
            <location>London</location>
        </house>
    </houses>
</people>

解决方案应该是通用的,因为我不想为对象图中的每个新元素编写额外的类。

为了完整起见,这里是宁静的网络服务:

@Path("rest/persons")
public class TestService {
    @GET
    @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_JSON })
    public Collection<Person> test() throws Exception {
        Collection<Person> persons = new ArrayList<Person>();
        Collection<House> houses = new HashSet<House>();
        houses.add(new House("MyAppartment", "London"));
        houses.add(new House("MySecondAppartment", "London"));
        persons.add(new Person("Thomas", houses));
        persons.add(new Person("Edward", houses));
        return persons;
    }
}

提前致谢。

【问题讨论】:

  • 我可以编写一个XmlAdapter 来返回包含所有值的子类House 的浅实例,或者只引用原始实例,是的。但是有很多缺点:(1)我必须为对象图中的每个类编写子类,(2)我必须在marshal()unmarshal()方法中添加所有@XmlAttributes,以及最后 (3) 它不会生成包含作为根节点子节点的房屋的 XML。更改模型时,我必须采用许多事情。所有这些都可以自动完成,因为所有信息都在那里。

标签: java jaxb xml-serialization jersey


【解决方案1】:

如果您尝试序列化为与您提供的最后一个 XML 示例匹配的格式,那么我相信您的对象图的结构不正确以实现这一目标。

如果您想提供Person 对象及其关联房屋的集合,并且还提供House 对象的集合,那么您需要返回包含这两个集合的序列化XML 消息。看起来好像您的 @XmlIDREF@XmlID 注释在正确的位置,以便按照您的意图(根据您的描述)建立人-房子关联,但您只返回 Person 对象的集合,而不是返回两个集合。

您的网络服务应该看起来更像这样(省略序列化,因为您很清楚如何序列化它):

@Path("rest/persons")
public class TestService {
    @GET
    @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_JSON })
    public Map<String, Object> test() throws Exception {
        Map<String, Object> peopleAndHouses = new HashMap<String, Object>();
        Collection<Person> persons = new ArrayList<Person>();
        Collection<House> houses = new HashSet<House>();

        houses.add(new House("MyAppartment", "London"));
        houses.add(new House("MySecondAppartment", "London"));
        persons.add(new Person("Thomas", houses));
        persons.add(new Person("Edward", houses));

        peopleAndHouses.put("houses", houses);
        peopleAndHouses.put("people", persons);
        return peopleAndHouses;
    }
}

还有其他方法可以实现这一点(例如,创建一个具有人和房屋的集合属性的包装器对象等),但希望您能明白这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多