Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring 4 REST program to return a List in XML using JAXB

I am trying to implement a REST service using Spring 4.

The REST method will return a list of customer objects in XML. The application is annotation-driven.

For XML, I have used JAXB annotations. As per my understanding, Spring will use "Jaxb2RootElementHttpMessageConverter" out-of-box when it finds JAXB annotations.

The Customer POJO:

@XmlRootElement(name = "customer")
public class Customer {
private int id;
private String name;
private List favBookList;
@XmlAttribute
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
@XmlElement
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}

@XmlElementWrapper(name = "booklist")
@XmlElement(name="book")
public List getFavBookList() {
    return favBookList;
}
public void setFavBookList(List favBookList) {
    this.favBookList = favBookList;
}
} 

I have annotated the REST service class as @RestController (as per Spring 4)

The REST method to return a list of customers in XML :

@RequestMapping(value="/customer-list.xml",produces="application/xml")
public  List<Customer> getCustomerListInXML(){
    List<Customer> customerList = new ArrayList<Customer>();
    Customer customerObj1 = new Customer();
    customerObj1.setId(1);
    customerObj1.setName("Vijay");
    ArrayList<String> favBookList1 = new ArrayList<String>();
    favBookList1.add("Book1");
    favBookList1.add("Book2");
    customerObj1.setFavBookList(favBookList1);
    customerList.add(customerObj1);
    Customer customerObj2 = new Customer();
    customerObj2.setId(2);
    customerObj2.setName("Rajesh");
    ArrayList<String> favBookList2 = new ArrayList<String>();
    favBookList2.add("Book3");
    favBookList2.add("Book4");
    customerObj2.setFavBookList(favBookList2);
    customerList.add(customerObj2);
    return customerList;
}

The result I expected, when I hit the URL :

 <customers>
  <customer id="1">
   <booklist>
    <book xsi:type="xs:string">Book1</book>
    <book xsi:type="xs:string">Book2</book>
   </booklist>
   <name>Vijay</name>
  </customer>
  <customer id="2">
   <booklist>
    <book xsi:type="xs:string">Book3</book>
    <book xsi:type="xs:string">Book4</book>
   </booklist>
   <name>Rajesh</name>
  </customer>
 </customers>

What I get :

HTTP 406 : The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.

Note :

When I try to return a Customer object in XML, it works as expected. However, I am unable to return a list of Customer objects in XML.

The application is developed using java 7 and it runs on Tomcat 7.

Need help with this. Thanks.

like image 351
Raj Singh Avatar asked Feb 03 '15 08:02

Raj Singh


2 Answers

I was able to generate an XML of the list of customers.

First create a generic wrapper class (The intent behind this is to use this generic class to pass a list of objects of any class).

The Generic Wrapper Class :

@XmlRootElement
@XmlSeeAlso({Customer.class})
public class EntityList<T> {

 private List<T> listOfEntityObjects;

    public EntityList() {
        listOfEntityObjects = new ArrayList<T>();
    }

    public EntityList(List<T> listOfEntityObjects) {
        this.listOfEntityObjects = listOfEntityObjects;
    }

    @XmlAnyElement
    public List<T> getItems() {
        return listOfEntityObjects;
    }

The modified REST method :

@RequestMapping(value="/customer-list.xml",produces="application/xml")
public  EntityList<Customer> getCustomerListInXML(){
    List<Customer> customerList = new ArrayList<Customer>();
    Customer customerObj1 = new Customer();
    customerObj1.setId(1);
    customerObj1.setName("Vijay");
    ArrayList<String> favBookList1 = new ArrayList<String>();
    favBookList1.add("Book1");
    favBookList1.add("Book2");
    customerObj1.setFavBookList(favBookList1);
    customerList.add(customerObj1);
    Customer customerObj2 = new Customer();
    customerObj2.setId(2);
    customerObj2.setName("Rajesh");
    ArrayList<String> favBookList2 = new ArrayList<String>();
    favBookList2.add("Book3");
    favBookList2.add("Book4");
    customerObj2.setFavBookList(favBookList2);
    customerList.add(customerObj2);
    EntityList<Customer> listOfCustomers =   
    new EntityList<Customer>  (customerList);

    return listOfCustomers;
}

The XML Response :

<entityList>
 <customer id="1">
  <booklist>
   <book xsi:type="xs:string">Book1</book>
   <book xsi:type="xs:string">Book2</book>
  </booklist>
  <name>Vijay</name>
 </customer>
 <customer id="2">
  <booklist>
   <book xsi:type="xs:string">Book3</book>
   <book xsi:type="xs:string">Book4</book>
  </booklist>
  <name>Rajesh</name>
 </customer>
</entityList>

Note :

The root element of the generated XML is entityList (which is taken from the name of the wrapper class)

However, I would like that the XML Root Element should be the plural of the entity name i.e customers in this case.

Any thoughts or suggestions?

like image 105
Raj Singh Avatar answered Nov 01 '22 12:11

Raj Singh


406 Not Acceptable The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.

Your back-end service is responding that the response type what it is returning is not provided/or it is different in the Accept-Type HTTP header in your request.

Find out the response content type returned by your server. Provide this content type in your request HTTP Accept header value. http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html HTTP Status codes

Other observations I think you should use parameterized type of List.

private List<String> favBookList; 
public List<String> getFavBookList() {
   return favBookList;
}
public void setFavBookList(List<String> favBookList) {
   this.favBookList = favBookList;
}
like image 1
FrAn Avatar answered Nov 01 '22 10:11

FrAn