使用JAXB解组/编组List <String>

Use*_*er1 45 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.Vector, and MIME media type,
application/octet-stream, was not found

我希望JAXB有一个简单类型的默认设置,如String,Integer等.我猜不是.这是我想象的:


<Strings>
  <String>a</String>
  <String>b</String>
</Strings>
Run Code Online (Sandbox Code Playgroud)

使这种方法有效的最简单方法是什么?

Use*_*er1 46

我使用@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;
    }
}

请注意,它使用泛型,因此您可以将其与String之外的其他类一起使用.现在,应用程序代码很简单:


    @GET
    @Path("/test2")
    public JaxbList test2(){
        List list=new Vector();
        list.add("a");
        list.add("b");
        return new JaxbList(list);
    }

为什么JAXB包中不存在这个简单的类?有人在别处看到类似的东西吗?


小智 32

@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();
}
Run Code Online (Sandbox Code Playgroud)

  • 2年后仍然有用:) (7认同)
  • 3年后仍然有用:) (5认同)
  • 这对我不起作用.使用Jersey 1.11 w/Glasfish 3.1.2.我得到`javax.ws.rs.WebApplicationException:com.sun.jersey.api.MessageException:Java类java.util.Vector的消息体编写器,Java类型java.util.List <java.lang.String>,和MIME媒体类型application/json未找到 (2认同)

Zou*_*ire 12

如果你们中的任何人想要为包含多个类的元素的列表编写列表包装器,并且想要根据类类型给出单独的XmlElement名称而不编写X Wrapper类,则可以使用@XmlMixed注释.通过这样做,JAXB根据设置的值命名列表的项目@XmlRootElement.这样做时,您必须使用指定列表中可能包含的类@XmlSeeAlso

例:

列表中可能的类

@XmlRootElement(name="user")
public class User {/*...*/}

@XmlRootElement(name="entry")
public class LogEntry {/*...*/}
Run Code Online (Sandbox Code Playgroud)

包装类

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

List l = new List();
l.add(new User("userA"));
l.add(new LogEntry(new UserB()));


XStream xStream = new XStream();
String result = xStream.toXML(l);
Run Code Online (Sandbox Code Playgroud)

结果:

<records>
    <user>...</user>
    <entry>...</entry>
</records>
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用@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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*rov 11

这是可以做到MUCH用美妙容易的XStream库.没有包装,没有注释.

目标XML

<Strings>
  <String>a</String>
  <String>b</String>
</Strings>
Run Code Online (Sandbox Code Playgroud)

序列化

(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);
Run Code Online (Sandbox Code Playgroud)

反序列化

反序列化为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);
Run Code Online (Sandbox Code Playgroud)

反序列化为String []

XStream xStream = new XStream();
xStream.alias("Strings", String[].class);
xStream.alias("String", String.class);
String[] result = (String[])xStream.fromXML(file);
Run Code Online (Sandbox Code Playgroud)

请注意,XStream实例是线程安全的,可以预先配置,将代码量缩减为一行.

XStream还可以用作JAX-RS服务的默认序列化机制.可在此处找到在Jersey中插入XStream的示例


Jér*_*nge 11

从个人博客文章中,没有必要创建特定JaxbList < T >对象.

假设一个对象带有一个字符串列表:

@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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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(" ");

}
Run Code Online (Sandbox Code Playgroud)

产生以下内容:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<objectWithList>
    <MyList>
        <list>Somewhere</list>
        <list>This and that</list>
        <list>Something</list>
    </MyList>
</objectWithList>
Run Code Online (Sandbox Code Playgroud)


Lio*_*orH 8

我曾经遇到过这种模式,我发现最简单的方法是用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);}
 }
Run Code Online (Sandbox Code Playgroud)

如果您使用javax.rs(jax-rs),我将返回Response对象,并将包装器设置为其实体