1

关于为什么列表类型不序列化的问题有很多,但是我质疑以简单的方式提供列表类型的 bean 的好做法是什么。

到目前为止,我一直在创建内部类来支持包装器,尽管我不喜欢管道,因为我需要为每个 pojo 做它。

客户类可能如下所示:

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

    private int id;
    private String name;

    // field accessors

    @XmlRootElement(name = "customers")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static final class CustomerList {
        private List<Customer> customer;
        public CustomerList() {
            this.customer = new ArrayList<>();
        }
        public DataList(List<Customer> list) {
            this.customer = list;
        }
        // customer accessors.
    }

}

我尝试制作一个通用类,XmlList<T>并在返回时创建新实例,但 JAXB 似乎不喜欢这样。

我在 Spring/MVC RESTful 应用程序中使用它,我需要同时支持 JSON 和 XML。我的 JSON 应该表示为一个数组,通过将实现放在 JSON 调用中,然后用 XML 调用包装,这使得该方法可以轻松实现。

4

4 回答 4

1

这是我如何做到这一点的。

@XmlRootElement // or @XmlTransient if you want to
public class Plural<S> {

    public static <P extends Plural<S>, S> P newInstance(
            final Class<P> pluralType, final Collection<S> elms) {
        P lt = (P) pluralType.newInstance();
        lt.singulars = new ArrayList<>(elms);
        return lt;
    }

    protected Collection<S> getSingulars() {
        if (singulars == null) {
            singulars = new ArrayList<S>();
        }
        return singulars;
    }

    private Collection<S> singulars;
}

然后,您可以制作任何单数类型的任何所需复数类型。也许你不喜欢你应该为所有单数类型创建所有复数类,但它可能真的很有帮助,尤其是当你想让那些客户端开发人员看起来更漂亮时。

@XmlRootElement
public class Customers extends Plural<Customer> {

    @XmlElement(name = "customer")
    public Collection<Customer> getCustomers() {
        return getSingulars();
    }
}

@XmlRootElement
public class Items extends Plural<Item> {

    @XmlElement(name = "item")
    public Collection<Item> getItems() {
        return getSingulars();
    }
}

@XmlRootElement
public class Invoices extends Plural<Invoice> {

    @XmlElement(name = "invoice")
    public Collection<Invoice> getInvoices() {
        return getSingulars();
    }
}

@XmlRootElement
public class BrettRyans extends Plural<BrettRyan> {

    @XmlElement(name = "brettRyan")
    public Collection<BrettRyan> getBrettRyans() {
        return getSingulars();
    }
}

根据布雷特瑞恩的评论更新

这里有功能齐全的源代码。

您可以在http://code.google.com/p/jinahya/source/browse/trunk/com.googlecode.jinahya/stackoverflow/查看完整的 mavenized 项目

如果您控制使用字段而不是属性,则 JAXB 不需要设置器。

@XmlTransient
public class Plural<S> {

    public static <P extends Plural<S>, S> P newInstance(
        final Class<P> pluralType) {
        return newInstance(pluralType, Collections.<S>emptyList());
    }

    public static <P extends Plural<S>, S> P newInstance(
        final Class<P> pluralType, final Collection<? extends S> singulars) {
        try {
            final P plural = pluralType.newInstance();
            plural.getSingulars().addAll(singulars);
            return plural;
        } catch (InstantiationException ie) {
            throw new RuntimeException(ie);
        } catch (IllegalAccessException iae) {
            throw new RuntimeException(iae);
        }
    }

    protected Collection<S> getSingulars() {
        if (singulars == null) {
            singulars = new ArrayList<S>();
        }
        return singulars;
    }

    private Collection<S> singulars;
}

@XmlAccessorType(XmlAccessType.NONE)
public class Item {

    public static Item newInstance(final long id, final String name) {
        final Item instance = new Item();
        instance.id = id;
        instance.name = name;
        return instance;
    }

    @Override
    public String toString() {
        return id + "/" + name;
    }

    @XmlAttribute
    private long id;

    @XmlValue
    private String name;
}

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class Items extends Plural<Item> {


    @XmlElement(name = "item")
    public Collection<Item> getItems() {
        return getSingulars();
    }
}

测试...

public class ItemsTest {

    @Test
    public void testXml() throws JAXBException, IOException {

        final Items marshallable = Plural.newInstance(Items.class);
        for (int i = 0; i < 5; i++) {
            marshallable.getItems().add(Item.newInstance(i, "name" + i));
        }
        for (Item item : marshallable.getItems()) {
            System.out.println("marshallable.item: " + item);
        }

        final JAXBContext context = JAXBContext.newInstance(Items.class);

        final Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        final ByteArrayOutputStream baos = new ByteArrayOutputStream();

        marshaller.marshal(marshallable, baos);
        baos.flush();

        final Unmarshaller unmarshaller = context.createUnmarshaller();
        final Items unmarshalled = (Items) unmarshaller.unmarshal(
            new ByteArrayInputStream(baos.toByteArray()));
        for (Item item : unmarshalled.getItems()) {
            System.out.println("unmarshalled.item: " + item);
        }
    }
}

印刷

marshallable.item: 1/name1
marshallable.item: 2/name2
marshallable.item: 3/name3
marshallable.item: 4/name4
unmarshalled.item: 0/name0
unmarshalled.item: 1/name1
unmarshalled.item: 2/name2
unmarshalled.item: 3/name3
unmarshalled.item: 4/name4

根据 Brett Ryan 的第二条评论更新

@Test
public void testXsd() throws JAXBException, IOException {

    final JAXBContext context = JAXBContext.newInstance(Items.class);

    context.generateSchema(new SchemaOutputResolver() {
        @Override
        public Result createOutput(final String namespaceUri,
                                   final String suggestedFileName)
            throws IOException {
            return new StreamResult(System.out) {
                @Override
                public String getSystemId() {
                    return "noid";
                }
            };
        }
    });
}

Plural@XmlRootElement.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="items" type="items"/>

  <xs:element name="plural" type="plural"/>

  <xs:complexType name="items">
    <xs:complexContent>
      <xs:extension base="plural">
        <xs:sequence>
          <xs:element name="item" type="item" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="plural">
    <xs:sequence/>
  </xs:complexType>

  <xs:complexType name="item">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="id" type="xs:long" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>

Plural@XmlTransient.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="items" type="items"/>

  <xs:complexType name="items">
    <xs:sequence>
      <xs:element name="item" type="item" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="item">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="id" type="xs:long" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>
于 2012-08-16T14:03:30.000 回答
0

供更多读者参考。

我刚刚发现了一篇有趣的博客文章,讨论了 JAX-RS 的自动复数。 https://blogs.oracle.com/PavelBucek/entry/returning_xml_representation_of_list

我不确定此功能是否特定于实现。

每个人都必须尝试平台服务的内容和方式。

@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<Item> read() {

    final List<Item> items = ... // is the variable name relevant 

    return items;
}
于 2012-08-20T12:23:26.140 回答
0

这可能是我认为的另一种正确方式。

@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response readItems() {

    final List<Item> items = ...;

    return Response.ok(new GenericEntity<List<String>>(list) {}).build();
}
于 2013-03-21T04:03:00.150 回答
0

很抱歉,我找到了另一种我认为更好的方法。

@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<Item> readItems() {

    final List<Item> items = itemBean.list(...);

    return items;
}

在这种情况下,任何应用程序服务器都可以以不同的方式生成。

与 GlassFish

<items> <!-- smart plural names -->
  <item xmlns="http://www.example.com">
    ...
  </item>
  <item xmlns="http://www.example.com">
    ...
  </item>
<items>

与 JBoss

<collection>
  <item xmlns="http://www.example.com">
    ...
  </item>
  <item xmlns="http://www.example.com">
    ...
  </item>
<collection>

对于客户来说,这个问题不是影响。可以像这样使用一般的 XPath 表达式。

"//item/name/first"
于 2013-05-05T14:13:59.080 回答