Using JAXB to undo / marshal the <String> list

I am trying to create a very simple REST server. I just have a testing method that will return a list of strings. Here is the code:

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

It produces the following error:

 SEVERE: A message body writer for Java type,
 class java.util.Vector, and MIME media type,
 application / octet-stream, was not found

I was hoping JAXB has a default setting for simple types like String, Integer, etc. I think no. Here is what I imagined:

 <Strings> <String>a</String> <String>b</String> </Strings> 

What is the easiest way to make this method work?

+43
java rest jaxb
Oct 21 '09 at 20:29
source share
11 answers

I used the @LiorH example and expanded it to:

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

Note that it uses generics, so you can use it with classes other than String. Now the application code is simple:

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

Why does this simple class not exist in the JAXB package? Does anyone see something like this elsewhere?

+46
Oct 21 '09 at 21:55
source share
 @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(); } 
+31
Jul 26 '10 at 9:28
source share

In case one of you wants to write a list wrapper for lists containing elements of several classes, and wants to give a separate XmlElement name according to the type of the class without entering Wrapper classes, you can use the @XmlMixed annotation. Thus, JAXB names the list items according to the value given by @XmlRootElement . In this case, you need to specify which classes can be in the list using @XmlSeeAlso

Example:

Possible classes in the list

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

Wrapper class

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

Example:

 List l = new List(); l.add(new User("userA")); l.add(new LogEntry(new UserB())); XStream xStream = new XStream(); String result = xStream.toXML(l); 

Result:

 <records> <user>...</user> <entry>...</entry> </records> 

Alternatively, you can specify the XmlElement names directly inside the wrapper class using the @XmlElementRef annotation

 @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; } } 
+12
Mar 06 2018-12-12T00:
source share

This can make MUCH easier using the wonderful XStream library. No wrappers, no annotations.

XML Target

 <Strings> <String>a</String> <String>b</String> </Strings> 

Serialization

( String alias can be avoided by using the String string tag, but I used the OP code)

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

Deserialization

Delialization in 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); 

Desalization in String []

 XStream xStream = new XStream(); xStream.alias("Strings", String[].class); xStream.alias("String", String.class); String[] result = (String[])xStream.fromXML(file); 

Note that the XStream instance is thread safe and can be preconfigured, reducing the amount of code to single-line.

XStream can also be used as the default serialization engine for the JAX-RS service. An example of connecting XStream in Jersey can be found here.

+11
Dec 08 2018-11-11T00:
source share

From the personal blog post , there is no need to create a specific JaxbList < T > object.

Assuming an object with a list of strings:

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

A round trip 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(" "); } 

Produces the following:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <objectWithList> <MyList> <list>Somewhere</list> <list>This and that</list> <list>Something</list> </MyList> </objectWithList> 
+9
Aug 07 '12 at 18:33
source share

I met this pattern several times, I found that the easiest way is to define an inner class with JaxB annotations. (in any case, you probably want to determine the name of the root tag)

so that your code looks something like this.

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

If you are working with javax.rs (jax-rs), I would return a Response object with the shell installed as its entity

+8
Oct 21 '09 at 20:42
source share

User1 example worked well for me. But, as a warning, it will not work with anything but the simple String / Integer types unless you add the @XmlSeeAlso annotation:

 @XmlRootElement(name = "List") @XmlSeeAlso(MovieTicket.class) public class MovieTicketList { protected List<MovieTicket> list; 

This works fine, although it prevents me from using one common list class in my entire application. It may also explain why this obvious class does not exist in the JAXB package.

+2
Mar 10 '10 at 15:44
source share

Finally, I solved it with JacksonJaxbJsonProvider It requires a few changes in your Spring context.xml and Maven pom.xml

In Spring context.xml add JacksonJaxbJsonProvider to <jaxrs:server> :

 <jaxrs:server id="restService" address="/resource"> <jaxrs:providers> <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/> </jaxrs:providers> </jaxrs:server> 

In your Maven pom.xml add:

 <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-jaxrs</artifactId> <version>1.9.0</version> </dependency> 
+2
Jun 11 '15 at 9:44
source share

Be sure to add the @XmlSeeAlso tag to your specific classes used inside JaxbList. This is very important, otherwise it throws an HttpMessageNotWritableException

0
Jun 06 '13 at 11:15
source share

I would save time if I found Resteasy Jackson Provider before.

Just add JS . No wrappers for objects. No XML Annotations. There are no authors of own posts.

0
Apr 23 '15 at 19:33
source share

If you are using maven in a jersey project, add below to pom.xml and update the project dependencies so that Jaxb can detect the model class and convert the list to an application like Media XML:

 <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> 
0
Jan 22 '17 at 23:42 on
source share



All Articles