使用JAXB解组/编组List <String>
我正在尝试创build一个非常简单的REST服务器。 我只是有一个testing方法,将返回一个string列表。 代码如下:
@GET @Path("/test2") public List test2(){ List list=new Vector(); list.add("a"); list.add("b"); return list; }
它给出了以下错误:
SEVERE:Javatypes的消息主体编写器, 类java.util.Vector和MIME媒体types, 应用程序/八位字节stream,没有被发现
我希望JAXB有一个像String,Integer等简单types的默认设置,我猜不是。 这是我所想象的:
<Strings> <String>a</String> <String>b</String> </Strings>
什么是最简单的方法来使这种方法的工作?
我使用了@LiorH的例子,并将其扩展为:
@XmlRootElement(name="List") public class JaxbList<T>{ protected List<T> list; public JaxbList(){} public JaxbList(List<T> list){ this.list=list; } @XmlElement(name="Item") public List<T> getList(){ return list; } }
@XmlRootElement(name="List") public class JaxbList<T>{ protected List<T> list; public JaxbList(){} public JaxbList(List<T> list){ this.list=list; } @XmlElement(name="Item") public List<T> getList(){ return list; } }
请注意,它使用generics,因此您可以将其与除String之外的其他类一起使用。 现在,应用程序代码很简单:
@GET @Path("/test2") public JaxbList test2(){ List list=new Vector(); list.add("a"); list.add("b"); return new JaxbList(list); }
@GET @Path("/test2") public JaxbList test2(){ List list=new Vector(); list.add("a"); list.add("b"); return new JaxbList(list); }
为什么JAXB包中不存在这个简单的类? 任何人都可以在其他地方看到任
@GET @Path("/test2") public Response test2(){ List<String> list=new Vector<String>(); list.add("a"); list.add("b"); final GenericEntity<List<String>> entity = new GenericEntity<List<String>>(list) { }; return Response.ok().entity(entity).build(); }
如果你们中的任何一个人想要为包含多个类的元素的列表编写一个列表包装器,并且希望根据类types给出一个单独的XmlElement名称而无需编写X Wrapper类,则可以使用@XmlMixed
注释。 通过这样做,JAXB根据@XmlRootElement
设置的值来命名列表项。 这样做时,必须使用@XmlSeeAlso
指定哪些类可能在列表中
例:
列表中可能的类
@XmlRootElement(name="user") public class User {/*...*/} @XmlRootElement(name="entry") public class LogEntry {/*...*/}
包装类
@XmlRootElement(name="records") @XmlSeeAlso({User.class, LogEntry.class}) public static class JaxbList<T>{ protected List<T> records; public JaxbList(){} public JaxbList(List<T> list){ this.records=list; } @XmlMixed public List<T> getRecords(){ return records; } }
例:
List l = new List(); l.add(new User("userA")); l.add(new LogEntry(new UserB())); XStream xStream = new XStream(); String result = xStream.toXML(l);
结果:
<records> <user>...</user> <entry>...</entry> </records>
换句话说,你可以使用@XmlElementRef
注解直接在包装类中指定XmlElement名称
@XmlRootElement(name="records") @XmlSeeAlso({User.class, LogEntry.class}) public static class JaxbList<T>{ protected List<T> records; public JaxbList(){} public JaxbList(List<T> list){ this.records=list; } @XmlElementRefs({ @XmlElementRef(name="item", type=Object.class), @XmlElementRef(name="user", type=User.class), @XmlElementRef(name="entry", type=LogEntry.class) }) public List<T> getRecords(){ return records; } }
这可以使用美妙的XStream库更容易完成。 没有包装,没有注释。
目标XML
<Strings> <String>a</String> <String>b</String> </Strings>
序列化
( String
别名可以通过使用小写string
标记来避免,但是我使用了OP的代码)
List <String> list = new ArrayList <String>(); list.add("a"); list.add("b"); XStream xStream = new XStream(); xStream.alias("Strings", List.class); xStream.alias("String", String.class); String result = xStream.toXML(list);
反序列化
反序列化到ArrayList
XStream xStream = new XStream(); xStream.alias("Strings", ArrayList.class); xStream.alias("String", String.class); xStream.addImplicitArray(ArrayList.class, "elementData"); List <String> result = (List <String>)xStream.fromXML(file);
反序列化成String []
XStream xStream = new XStream(); xStream.alias("Strings", String[].class); xStream.alias("String", String.class); String[] result = (String[])xStream.fromXML(file);
请注意,XStream实例是线程安全的,可以预先configuration,将代码量缩减为一行。
XStream也可以用作JAX-RS服务的默认序列化机制。 可以在这里find在泽西插入XStream的例子
从个人博客文章 ,没有必要创build一个特定的JaxbList < T >
对象。
假设有一个string列表的对象:
@XmlRootElement public class ObjectWithList { private List<String> list; @XmlElementWrapper(name="MyList") @XmlElement public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } }
JAXB往返:
public static void simpleExample() throws JAXBException { List<String> l = new ArrayList<String>(); l.add("Somewhere"); l.add("This and that"); l.add("Something"); // Object with list ObjectWithList owl = new ObjectWithList(); owl.setList(l); JAXBContext jc = JAXBContext.newInstance(ObjectWithList.class); ObjectWithList retr = marshallUnmarshall(owl, jc); for (String s : retr.getList()) { System.out.println(s); } System.out.println(" "); }
产生以下内容:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <objectWithList> <MyList> <list>Somewhere</list> <list>This and that</list> <list>Something</list> </MyList> </objectWithList>
我遇到过这种模式几次,我发现最简单的方法是用JaxB注释定义一个内部类。 (无论如何,你可能想要定义根标签名称)
所以你的代码看起来像这样
@GET @Path("/test2") public Object test2(){ MyResourceWrapper wrapper = new MyResourceWrapper(); wrapper .add("a"); wrapper .add("b"); return wrapper ; } @XmlRootElement(name="MyResource") private static class MyResourceWrapper { @XmlElement(name="Item") List<String> list=new ArrayList<String>(); MyResourceWrapper (){} public void add(String s){ list.add(s);} }
如果你使用javax.rs(jax-rs),那么我会返回Response对象,将包装器设置为它的实体
User1的例子对我很好。 但是,作为一个警告,除了简单的String / Integertypes之外,它将不能使用,除非添加@XmlSeeAlso注解:
@XmlRootElement(name = "List") @XmlSeeAlso(MovieTicket.class) public class MovieTicketList { protected List<MovieTicket> list;
这工作正常,但它阻止我在整个应用程序中使用单个通用列表类。 这也可以解释为什么这个看似明显的类不存在于JAXB包中。
最后,我用JacksonJaxbJsonProvider
解决了这个问题。在你的Spring context.xml
和Maven pom.xml
需要做一些修改
在你的Spring context.xml
添加JacksonJaxbJsonProvider
到<jaxrs:server>
:
<jaxrs:server id="restService" address="/resource"> <jaxrs:providers> <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/> </jaxrs:providers> </jaxrs:server>
在你的Maven pom.xml中添加:
<dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-jaxrs</artifactId> <version>1.9.0</version> </dependency>
确保添加@XmlSeeAlso标记与您在JaxbList中使用的特定类。 这是非常重要的,它抛出HttpMessageNotWritableException
如果我更快地findResteasy Jackson Provider,我会节省时间的。
只需添加Resteasy Jackson提供程序JAR即可 。 没有实体包装。 没有XML注释。 没有自定义消息正文的作家。
如果你在jersey项目中使用maven,请在pom.xml中添加以下内容并更新项目依赖关系,以便Jaxb能够检测模型类并将列表转换为媒体types应用程序XML:
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency>