关于为什么列表类型不是序列化的问题有很多问题,但是我质疑以简单的方式提供列表类型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调用包装来轻松地促进它。
答案 0 :(得分: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();
}
}
根据Brett Ryan的评论更新
这里有全功能的源代码。
您可以在http://code.google.com/p/jinahya/source/browse/trunk/com.googlecode.jinahya/stackoverflow/
看到完整的mavenized项目如果你控制使用字段而不是属性,则JAXB不需要setter。
@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>
答案 1 :(得分: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;
}
答案 2 :(得分: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();
}
答案 3 :(得分: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"