Java 使用JAXB解组/封送列表<;字符串>;
我正在尝试创建一个非常简单的REST服务器。我有一个测试方法,它将返回一个字符串列表。代码如下:Java 使用JAXB解组/封送列表<;字符串>;,java,rest,jaxb,Java,Rest,Jaxb,我正在尝试创建一个非常简单的REST服务器。我有一个测试方法,它将返回一个字符串列表。代码如下: @GET @Path("/test2") public List test2(){ List list=new Vector(); list.add("a"); list.add("b"); return list; } 它给出了以下错误: SEVERE: A message body writer for Java type, class java.util.V
@GET
@Path("/test2")
public List test2(){
List list=new Vector();
list.add("a");
list.add("b");
return list;
}
它给出了以下错误:
SEVERE: A message body writer for Java type,
class java.util.Vector, and MIME media type,
application/octet-stream, was not found
严重:Java类型的消息体编写器,
类java.util.Vector和MIME媒体类型,
找不到应用程序/八位字节流
我希望JAXB对字符串、整数等简单类型有一个默认设置。我想没有。以下是我的想象:
<Strings>
<String>a</String>
<String>b</String>
</Strings>
A.
B
让这个方法工作的最简单的方法是什么?我已经多次遇到这种模式,我发现最简单的方法是用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);}
}
@GET
@路径(“/test2”)
公共对象test2(){
MyResourceWrapper=新的MyResourceWrapper();
(a)加入(“a”);
(b)加入(“b”);
返回包装器;
}
@XmlRootElement(name=“MyResource”)
私有静态类MyResourceWrapper{
@xmlement(name=“Item”)
列表=新的ArrayList();
MyResourceWrapper(){}
public void add(字符串s){list.add(s);}
}
如果您使用javax.rs(jax-rs),我将返回响应对象,并将包装器集作为其实体我使用了@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;
}
}
为什么JAXB包中不存在这个简单的类?有人在其他地方看到过类似的东西吗?User1的例子对我很有用。但是,作为一个警告,除了简单的字符串/整数类型之外,它不适用于任何其他类型,除非您添加@xmlseeald注释:
@XmlRootElement(name = "List")
@XmlSeeAlso(MovieTicket.class)
public class MovieTicketList {
protected List<MovieTicket> list;
@XmlRootElement(name=“List”)
@XMLSEEALLO(MovieTicket.class)
公共级电影目录{
受保护名单;
虽然它阻止我在整个应用程序中使用单一的泛型列表类,但它仍然可以正常工作。这也可以解释为什么JAXB包中不存在这个看似显而易见的类。@GET
@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();
}
@路径(“/test2”)
公众回应测试2(){
列表=新向量();
列表。添加(“a”);
列表。添加(“b”);
最终通用实体=新通用实体(列表){};
返回Response.ok().entity(entity.build();
}
使用美妙的库,这可以更轻松地完成。无包装,无注释
目标XML
反序列化
反序列化为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);
注意,XStream实例是线程安全的,可以预先配置,从而将代码量缩减到一行
XStream还可以用作JAX-RS服务的默认序列化机制。在Jersey中插入XStream的示例可以找到以防任何人想要为包含多个类的元素的列表编写一个列表包装器,并且想要根据类类型给出一个单独的XmlElement名称,而不需要编写X包装器cla您可以使用
@XmlMixed
注释。
通过这样做,JAXB根据@XmlRootElement
设置的值命名列表中的项。
执行此操作时,您必须使用@xmlsee也
示例:
列表中可能的类
@XmlRootElement(name=“user”)
公共类用户{/*…*/}
@XmlRootElement(name=“entry”)
公共类日志项{/*…*/}
包装类
@XmlRootElement(name=“records”)
@XMLSEEALLO({User.class,LogEntry.class})
公共静态类JaxbList{
受保护名单记录;
公共JaxbList(){}
公共JaxbList(列表){
这个。记录=列表;
}
@混合
公共列表记录(){
退货记录;
}
}
例如:
List l=新列表();
l、 添加(新用户(“用户A”);
l、 添加(新日志条目(新UserB());
XStream XStream=新的XStream();
字符串结果=xStream.toXML(l);
结果:
...
...
或者,您可以使用@xmlementref
注释直接在包装类内部指定xmlement名称
@XmlRootElement(name=“records”)
@XMLSEEALLO({User.class,LogEntry.class})
公共静态类JaxbList{
受保护名单记录;
公共JaxbList(){}
公共JaxbList(列表){
这个。记录=列表;
}
@XmlElementRefs({
@xmlementref(name=“item”,type=Object.class),
@xmlementref(name=“user”,type=user.class),
@xmlementref(name=“entry”,type=LogEntry.class)
})
公共列表记录(){
退货记录;
}
}
从个人博客中,无需创建特定的JaxbList
对象
假设对象具有字符串列表:
@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;
}
}
@XmlRootElement
公共类ObjectWithList{
私人名单;
@XmlElementWrapper(name=“MyList”)
@XmlElement
公共列表getList(){
退货清单;
}
公共无效集合列表(列表){
this.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(" ");
}
public static void simpleExample()抛出JAXBEException{
列表l=新的ArrayList();
l、 添加(“某处”);
l、 添加(“这个和那个”);
l、 添加(“某物”);
//具有列表的对象
ObjectWithList owl=新建ObjectWithList();
owl.集合列表(l);
JAXBContext jc=JAXBContext.newInstance(ObjectWithList.class);
ObjectWithList retr=MarshallLunmarshall(owl,jc);
for(字符串s:retr.getList()){
系统输出打印项次;
}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>
某处
这个和那个
某物
确保在JaxbList中添加带有特定类的@xmlseea标记。这一点非常重要,否则它会引发HttpMessageNotWritableException如果我早点找到Resteasy Jackson Provider我会节省时间
只需添加Resteasy Jackson提供程序JAR。无实体包装、无XML注释、无自定义消息正文编写器。最后,我使用
XStream xStream = new XStream();
xStream.alias("Strings", String[].class);
xStream.alias("String", String.class);
String[] result = (String[])xStream.fromXML(file);
@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;
}
}
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>
<jaxrs:server id="restService" address="/resource">
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
public class Wrapper<T> {
private List<T> items = new ArrayList<T>();
@XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
}
//JAXBContext is thread safe and so create it in constructor or
//setter or wherever:
...
JAXBContext jc = JAXBContext.newInstance(Wrapper.class, clazz);
...
public String marshal(List<T> things, Class clazz) {
//configure JAXB and marshaller
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//Create wrapper based on generic list of objects
Wrapper<T> wrapper = new Wrapper<T>(things);
JAXBElement<Wrapper> wrapperJAXBElement = new JAXBElement<Wrapper>(new QName(clazz.getSimpleName().toLowerCase()+"s"), Wrapper.class, wrapper);
StringWriter result = new StringWriter();
//marshal!
m.marshal(wrapperJAXBElement, result);
return result.toString();
}