How To Write a Java Client for DELETE Method Rest Service

DELETE method is used in REST service to delete data on the server. When deleting the right way to do it is using the DELETE method to send message to REST service.  If matching id is found the data on the server will be deleted.  Let us see an example of how to call such a REST service and delete the data on the server.

Service Class

DeleteJsonService.java

In this class the method maps to DELETE method.  When the request comes to the service, the client send a book id as request parameter.  The service then iterates the Books in the system and if it finds the id it deletes the Book and sends back the remaining books to the client.  The input parameter is captured in the @PathParam(“bookId”) int bookId and then it is matched with the books  in the system.

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.freetipscentral.utility.BookCreator;

@Path("/deleteJSON")
public class DeleteJsonService {

  @Produces(MediaType.APPLICATION_JSON)
  @DELETE
  @Consumes(MediaType.APPLICATION_JSON)
  @Path("/{bookId}")
  public List<Book> deleteBook(@PathParam("bookId") int bookId ) {
    List<Book> books = BookCreator.getBooks();
    for(Book eachBook : books)  {
      if(eachBook.getSerialNumber() == bookId) {
        books.remove(eachBook);
      }
    }
    return books;
  }
}

Domain Class

Book.java

package com.freetipscentral.domain;
 
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement
public class Book {
 
  String name;
  int serialNumber;
 
  public Book() {}
 
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public int getSerialNumber() {
    return serialNumber;
  }
 
  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }
 
  public String toString() {
    return serialNumber + " "  + name;
  }	
}

Utility Class To Create Book List on Server

BookCreator.java

This class has a static method to create two book objects and return the list.

package com.freetipscentral.utility;
 
import java.util.ArrayList;
import java.util.List;
 
import com.freetipscentral.domain.Book;
 
public class BookCreator {
 
  public static List<Book> getBooks() {
    List<Book> books = new ArrayList<Book>();
    Book book1 = new Book("Head First Java",1);
    Book book2 = new Book("Head First Design Pattern",2);
    books.add(book1);
    books.add(book2);
    return books;
  }
}

Here is the DELETE client

JerseyRestDeleteClient.java

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;

public class JerseyRestDeleteClient {
  public static void main(String args[]) {
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:8080/RestWebService/rest/deleteJSON/1");
    List<Book> response =resource.type(MediaType.APPLICATION_JSON)
    .accept(MediaType.APPLICATION_JSON)
    .delete(new GenericType<List<Book>>(){});
    
    for(Book eachBook : response){
      System.out.println(eachBook);
    }
  }
}

Here is the Output

As you can see, the id for the book 1 matched the input book id hence it was deleted.  Rest of the books were returned.

2 Head First Design Pattern

 

Video Version of this Tutorial

I have also create a video tutorial and you can find it here –

How To Write a Java Client for PUT Method Rest Service

PUT method is used in REST service to update data. Usually you will use the PUT method to send message to REST service.  If matching id is found the data on the server will be updated.  Let us see an example of how to call such a REST service and update the data on the server.

Service Class

PutJsonService.java

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.freetipscentral.utility.BookCreator;

@Path("/putJSON")
public class PutJsonService {

  @Produces(MediaType.APPLICATION_JSON)
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public List<Book> getBookAsJSON(Book book) {
    List<Book> books = BookCreator.getBooks();
    for(Book eachBook : books)  {
      if(book.getSerialNumber() == eachBook.getSerialNumber()) {
        eachBook.setName(book.getName());
      }
    }
    return books;
  }
}

Domain Class

Book.java

 

package com.freetipscentral.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Book {
  
  String name;
  int serialNumber;
  
  public Book() {}
  
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getSerialNumber() {
    return serialNumber;
  }

  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }

  public String toString() {
    return serialNumber + " "  + name;
  }	
}

Utility Class To Create Book List on Server

BookCreator.java

This class has a static method to create two book objects and return the list.

 

package com.freetipscentral.utility;

import java.util.ArrayList;
import java.util.List;

import com.freetipscentral.domain.Book;

public class BookCreator {
  
  public static List<Book> getBooks() {
    List<Book> books = new ArrayList<Book>();
    Book book1 = new Book("Head First Java",1);
    Book book2 = new Book("Head First Design Pattern",2);
    books.add(book1);
    books.add(book2);
    return books;
  }

}

Here is the PUT client

JerseyRestPutClient.java

 

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;

public class JerseyRestPutClient {
  public static void main(String args[]) {
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:8080/RestWebService/rest/putJSON");
    Book book = new Book("Deep Work",1);
    List<Book> response =resource.type(MediaType.APPLICATION_JSON)
    .accept(MediaType.APPLICATION_JSON)
    .put(new GenericType<List<Book>>(){},book);
    
    for(Book eachBook : response){
      System.out.println(eachBook);
    }
  }
}

Here is the Output

As you can see, the book 1 which was originally Head First Java was changed to Deep Work.

1 Deep Work
2 Head First Design Pattern

Video Version of Tutorial

Here is the video version of this tutorial I have created.

Java Client To Get Xml Or JSON List From Get Method in Rest Service

We saw previously how to get XML data using a a Java Client from a Rest service.  In this post we will see how to get List of objects from Xml and Json from a Rest service in a Java client.

We will basically use the same structure as the previous post but the with a little difference to handle List.  Here are the classes.

Here is the Domain class.

Book.class

package com.freetipscentral.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Book {
  
  String name;
  int serialNumber;
  
  public Book() {}
  
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getSerialNumber() {
    return serialNumber;
  }

  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }

  public String toString() {
    return serialNumber + " "  + name;
  }	
}

 

To get JSON response here are the Service and Client Classes.

Service class.

RestXMLService.java

package com.freetipscentral;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;

@Path("/getXML")
public class RestXMLService {

  @Produces(MediaType.APPLICATION_JSON)
  @GET
  public List<Book> getBookAsXML() {
    
    Book book1 = new Book("Head First Java", 1);
    Book book2 = new Book("Head First Design Patterns", 2);
    
    List<Book> bookList = new ArrayList<Book>();
    bookList.add(book1);
    bookList.add(book2);
    return bookList;
  }
}

Client for JSON

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;

public class JerseyRestGettClient {
  public static void main(String args[]) {
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:8080/RestWebService/rest/getXML");
    
    List<Book> response =resource
    .accept(MediaType.APPLICATION_JSON)
    .get(new GenericType<List<Book>>(){});
    
    for(Book book : response){
      System.out.println(book);
    }
  }
}

To get XML response here are the Service and Client Classes.

Service class.

RestXMLService.java

package com.freetipscentral;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;

@Path("/getXML")
public class RestXMLService {

  @Produces(MediaType.APPLICATION_XML)
  @GET
  public List<Book> getBookAsXML() {
    
    Book book1 = new Book("Head First Java", 1);
    Book book2 = new Book("Head First Design Patterns", 2);
    
    List<Book> bookList = new ArrayList<Book>();
    bookList.add(book1);
    bookList.add(book2);
    return bookList;
  }
}

Client for XML

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;

public class JerseyRestGettClient {
  public static void main(String args[]) {
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:8080/RestWebService/rest/getXML");
    
    List<Book> response =resource
    .accept(MediaType.APPLICATION_XML)
    .get(new GenericType<List<Book>>(){});
    
    for(Book book : response){
      System.out.println(book);
    }
  }
}

Here are the jar files needed

The jar files required are as follows

  • genson-1.3.jar
  • jersey-bundle-1.9.jar
  • jersey-core-1.8.jar

Here is the output

1 Head First Java
2 Head First Design Patterns

Here is the video version

 

Java Client To Get Xml Response From GET Method

Getting response from a REST service from a POST request, using a Java client is very simple as we saw in this example.  In this tutorial we will see how to get a response from GET method from a REST method.  We will again use a Java client for this.

Here is the Service class

RestXMLService.java

package com.freetipscentral;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;

@Path("/getXML")
public class RestXMLService {

  @Produces(MediaType.APPLICATION_XML)
  @GET
  public Book getBookAsXML() {
    
    Book book1 = new Book("Head First Java", 1);
    
    return book1;
  }
}

Domain class.

Book.java

package com.freetipscentral.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Book {
  
  String name;
  int serialNumber;
  
  public Book() {}
  
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getSerialNumber() {
    return serialNumber;
  }

  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }

  public String toString() {
    return serialNumber + " "  + name;
  }	
}

REST Client

JerseyRestGetClient.java

package com.freetipscentral;

import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;

public class JerseyRestGetClient {
  public static void main(String args[]) {
    
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:8080/RestWebService/rest/getXML");
    
    Book response =resource.accept(MediaType.APPLICATION_XML)
    .get(Book.class);
    
    System.out.println(response);
  }
}

The jar files required are as follows

  • genson-1.3.jar
  • jersey-bundle-1.9.jar
  • jersey-core-1.8.jar

Here is the output

 

1 Head First Java

Solved : A message body reader for Java class and MIME media type application/xml was not found

If you are writing a REST client with Jersey and expecting a XML response which will be converted to Java object you may get MIME media type application/xml was not found exception.

For example see the following client code

package  com.freetipscentral;

import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;

public class JerseyRestGetClient {
  public static void main(String args[]) {
    
    Client client = Client.create();
    WebResource resource = client.resource("http://localhost:8080/RestWebService/rest/getXML");
    
    Book response =resource.accept(MediaType.APPLICATION_XML)
    .get(Book.class);
    
    System.out.println(response);
  }
}

This code can generate the following error –

Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class com.freetipscentral.domain.Book, and Java type class com.freetipscentral.domain.Book, and MIME media type application/xml was not found
  at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:549)
  at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)xx

The main reason is The Book.java class has no XMLRootElement Mapping as follows.

package com.freetipscentral.domain;

public class Book {
  
  String name;
  int serialNumber;
  
  public Book() {}
  
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getSerialNumber() {
    return serialNumber;
  }

  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }

  public String toString() {
    return serialNumber + " "  + name;
  }	
}

Due to the above condition the xml coming back from the REST service is not converted to Java object.  The solution is to add the XmlRootElelement annotation as follows.

package com.freetipscentral.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Book {
  
  String name;
  int serialNumber;
  
  public Book() {}
  
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getSerialNumber() {
    return serialNumber;
  }

  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }

  public String toString() {
    return serialNumber + " "  + name;
  }	
}

Doing this will resolve the problem of  MIME media type application/xml was not found.

Jersey Client To Get JSON Response From POST Method

In one of the previous tutorial how to post JSON list to REST service as arrayList we saw how to handle POST request which submitted JSON data and returned list JSON as output from the service.  To test the service we used a chrome based REST client called Postman.  In this article we will see how to write a Java client based on Jersey API to post request to the service and receive the response back from the service.

Here is the Service Class

PostJsonService.java 

package com.freetipscentral;
 
import java.util.List;
 
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
 
import com.freetipscentral.domain.Book;
import com.freetipscentral.domain.Books;
import com.freetipscentral.utility.BookCreator;
 
@Path("/postJSON")
public class PostJsonService {
 
	@Produces(MediaType.APPLICATION_JSON)
	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public List<Book> getBookAsJSON(Books books) {
		List<Book> bookList = BookCreator.getBooks();
		bookList.addAll(books.getBooks());
 
		return bookList;
	}
}

Here are the domain classes.

Book.java

package com.freetipscentral.domain;
 
public class Book {
 
	String name;
	int serialNumber;
 
	public Book() {}
 
	public Book(String name, int serialNumber) {
		this.name = name;
		this.serialNumber = serialNumber;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public int getSerialNumber() {
		return serialNumber;
	}
 
	public void setSerialNumber(int serialNumber) {
		this.serialNumber = serialNumber;
	}
 
	public String toString() {
		return serialNumber + " "  + name;
	}	
}

Books.java

package com.freetipscentral.domain;
 
import java.util.List;
 
public class Books {
 
	List<Book> books;
	int totalPrice;
 
	public List<Book> getBooks() {
		return books;
	}
	public void setBooks(List<Book> books) {
		this.books = books;
	}
	public int getTotalPrice() {
		return totalPrice;
	}
	public void setTotalPrice(int totalPrice) {
		this.totalPrice = totalPrice;
	}
 
 
}

Here is a Helper Class

BookCreator.java

package com.freetipscentral.utility;
 
import java.util.ArrayList;
import java.util.List;
 
import com.freetipscentral.domain.Book;
 
public class BookCreator {
 
	public static List<Book> getBooks() {
		List<Book> books = new ArrayList<Book>();
		Book book1 = new Book("Head First Java",1);
		Book book2 = new Book("Head First Design Pattern",2);
		books.add(book1);
		books.add(book2);
		return books;
	}
 
}

Finally here is the Java client for the Rest Service

I have used Jersey 1.9

RestClient.java

In the client class 3 book objects are created and posted to the REST service.  The Rest service adds the 3 books to its pre-existing list of 2 books and then return the 5 books to the client.  The client then prints the books in console.

package com.freetipscentral.client;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.ws.rs.core.MediaType;
 
import com.freetipscentral.domain.Book;
import com.freetipscentral.domain.Books;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
 
public class RestClient {
	public static void main(String args[]) {
 
		Books books = new Books();
 
		Book book1 = new Book("Head First Java",1);
		Book book2 = new Book("Head First Design Pattern",2);
		Book book3 = new Book("My Experiments With Truth",3);
 
		List<Book> bookList = new ArrayList<Book>();
		bookList.add(book1);
		bookList.add(book2);
		bookList.add(book3);
		books.setBooks(bookList);
		books.setTotalPrice(100);
 
		Client client = Client.create();
		WebResource webResource = client.resource("http://localhost:8080/RestWebService/rest/postJSON");
 
		List<Book> booksFromRest = webResource.type(MediaType.APPLICATION_JSON)
				      .accept(MediaType.APPLICATION_JSON)
				      .post(new GenericType<List<Book>>() {}, books);
		for(Book eachBook : booksFromRest) {
			System.out.println(eachBook);
		}
	}
}

The jar files required for the client are as follows

  • genson-1.3.jar
  • jersey-bundle-1.9.jar
  • jersey-core-1.8.jar

Here is the Output

1 Head First Java
2 Head First Design Pattern
1 Head First Java
2 Head First Design Pattern
3 My Experiments With Truth

How To Resolve com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 1 expected } but read ”’ !

While dealing with JSON data you may sometimes run into following kind of error –

Caused by: com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 1 expected } but read ”’ !
at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:951)
at com.owlike.genson.stream.JsonReader.end(JsonReader.java:437)
at com.owlike.genson.stream.JsonReader.endObject(JsonReader.java:179)
at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:113)
at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:92)
at com.owlike.genson.convert.NullConverter$NullConverterWrapper.deserialize(NullConverter.java:56)
at com.owlike.genson.Genson.deserialize(Genson.java:389)

Usually this is caused by JSON object having single quotes.  For example if you have a JSON with the following structure

{'books':
   [
	{
	  'name':'My Experiments With Truth',
	  'serialNumber':3
     },
     {
       'name':'Deep Work',
	   'serialNumber':4
     },
     {
       'name':'So Good They Cannot Ignore You',
	   'serialNumber':5
     }
   ],
 'totalPrice':100
}

… and it is sent to a REST web service like the example here, you will get the above error.  The reason is very simple.  As you can notice the field names are enclosed in single quotes.  For example you can see ‘name’:’My Experiments With Truth’,  name and the value are enclose in single quotes.

To solve it put the values in double quotes.  Here is how the JSON should be.

{
 
 "books": [
  {
    "name": "Head First Java",
    "serialNumber": 1
  },
  {
    "name": "Head First Design Pattern",
    "serialNumber": 2
  },
  {
    "name": "My Experiments With Truth",
    "serialNumber": 3
  }],
  "totalPrice" :100
}

References – http://stackoverflow.com/questions/14355655/jquery-parsejson-single-quote-vs-double-quote

How To Post JSON List To REST Service As ArrayList

In the previous tutorial we saw how to POST XML List to a Jersey REST web service as ArrayList.  We sent a simple xml structure which represented a book.  What about sending a JSON list instead of XML list?

In this tutorial we will learn how to send a list of books in JSON format to the REST service using POST method.  The JSON List will be contained in a structure which will map to Books class as you can see below.

The service should accept the books sent and add them to the book list available in the system.  The service will then return back a list which contains pre-existing books in the system along with the books sent to the service.

Here is How the Service works

The REST service takes a list of Book objects and their price in a Books object in JSON format using POST method.  Although the totalPrice of books is sent it is mainly for demonstration purpose.  The price is not processed.  It is sent just to show that we can send other elements along with book list.

The service is annotated with @POST so that POST method can be used from the client.  This service takes JSON data as input and it gets converted to Books object which has structure to match the JSON input.  The Books class is a container class which contains list of book objects and a price field.

Service then retrieves a list of books from a utility class and adds the books sent to the method.  Then the list is sent back to the client.

To create a list of books a utility method has been created in the BookCreator class.  That class simply returns a list which contains two Book objects.

To receive the book as JSON two things are needed.

The input JSON should be mapping to the structure of the Books class.  You will see the example below.  The Content-Type should be application/json.

 

PostXmlService.java

package com.freetipscentral;
 
import java.util.List;
 
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
 
import com.freetipscentral.domain.Book;
import com.freetipscentral.domain.Books;
import com.freetipscentral.utility.BookCreator;
 
@Path("/postXML")
public class PostXmlService {
 
	@Produces(MediaType.APPLICATION_JSON)
	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public List<Book> getBookAsJSON(Books books) {
		List<Book> bookList = BookCreator.getBooks();
		bookList.addAll(books.getBooks());
 
		return bookList;
	}
}

Book.java

package com.freetipscentral.domain;
 
public class Book {
 
	String name;
	int serialNumber;
 
	public Book() {}
 
	public Book(String name, int serialNumber) {
		this.name = name;
		this.serialNumber = serialNumber;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public int getSerialNumber() {
		return serialNumber;
	}
 
	public void setSerialNumber(int serialNumber) {
		this.serialNumber = serialNumber;
	}
 
	public String toString() {
		return serialNumber + " "  + name;
	}	
}

Books.java

[codesyntax lang=”java”]

package com.freetipscentral.domain;

import java.util.List;

public class Books {
	
	List<Book> books;
	int totalPrice;
	
	public List<Book> getBooks() {
		return books;
	}
	public void setBooks(List<Book> books) {
		this.books = books;
	}
	public int getTotalPrice() {
		return totalPrice;
	}
	public void setTotalPrice(int totalPrice) {
		this.totalPrice = totalPrice;
	}
		
}

[/codesyntax]

BookCreator.java

package com.freetipscentral.utility;
 
import java.util.ArrayList;
import java.util.List;
 
import com.freetipscentral.domain.Book;
 
public class BookCreator {
 
	public static List<Book> getBooks() {
		List<Book> books = new ArrayList<Book>();
		Book book1 = new Book("Head First Java",1);
		Book book2 = new Book("Head First Design Pattern",2);
		books.add(book1);
		books.add(book2);
		return books;
	}
 
}

Here is the input Body

{
 
 "books": [
  {
    "name": "Head First Java",
    "serialNumber": 1
  },
  {
    "name": "Head First Design Pattern",
    "serialNumber": 2
  },
  {
    "name": "My Experiments With Truth",
    "serialNumber": 3
  }],
  "totalPrice" :100
}

Input Header

Content-Type  application/json

Here is the Output

[
 {
 "name": "Head First Java",
 "serialNumber": 1
 },
 {
 "name": "Head First Design Pattern",
 "serialNumber": 2
 },
 {
 "name": "Head First Java",
 "serialNumber": 1
 },
 {
 "name": "Head First Design Pattern",
 "serialNumber": 2
 },
 {
 "name": "My Experiments With Truth",
 "serialNumber": 3
 }
]

Here is the Video version of this tutorial

How to POST XML List To REST Service As ArrayList

In one of the previous tutorials we saw how to POST XML data to a Jersey REST webservice.  We sent a simple xml structure which represented a book.  In this tutorial we will learn how to send a list of books to the REST service using POST method.  The service should add the books sent to the service and then return back a list which contains pre-existing books in the system along with the books sent to the service.

Here is how the service works

The REST service takes a list of Book objects as XML using POST method.  The input also contains price of the books.  The price is not processed.  It is sent just to show that we can send other elements along with book list.

The service is annotated with @POST so that POST method can be used from the client.  This service takes Xml data as input and it gets converted to Books object which has structure to match the XML input.  The Books class is a container class which contains list of book objects and a price field.  It matches with the input from the XML.

Service then retrieves a list of books from a utility class and adds the books sent to the method.  Then the list is sent back to the client.

To create a list of books a utility method has been created in the BookCreator class.  That class simply returns a list which contains two Book objects.

To receive the book as XML two things are needed.

The Books class should be annotated with following –

@XmlRootElement(name =”books”)

The name attribute attribute indicates that the root element the xml data sent from the client should be named “book”.

The Book class

should be annotated with following –

@XmlRootElement(name =”book”)

Here are the classes you need.

PostXmlService.java

package com.freetipscentral;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.freetipscentral.domain.Book;
import com.freetipscentral.domain.Books;
import com.freetipscentral.utility.BookCreator;

@Path("/postXML")
public class PostXmlService {

  @Produces(MediaType.APPLICATION_XML)
  @POST
  @Consumes(MediaType.APPLICATION_XML)
  public List<Book> getBookAsXMLList(Books bookSet) {
    List<Book> books = BookCreator.getBooks();
    books.addAll(bookSet.getBooks());
    
    return books;
  }
}

Book.java

package com.freetipscentral.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name ="book")
public class Book {
  
  String name;
  int serialNumber;
  
  public Book() {}
  
  public Book(String name, int serialNumber) {
    this.name = name;
    this.serialNumber = serialNumber;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getSerialNumber() {
    return serialNumber;
  }

  public void setSerialNumber(int serialNumber) {
    this.serialNumber = serialNumber;
  }

  public String toString() {
    return serialNumber + " "  + name;
  }	
}

Books.java

The Books class should have @XmlElement(name=”book”) annotation for the books field which is the ArrayList of Book class.  This part is crucial.  This tells that books field maps to “book” element in the XML.  It also needs @XmlRootElement(name =”books”) at the class level.  The class should also be annotated with  @XmlAccessorType(XmlAccessType.FIELD) so as to avoid conflict for the annotating book.

package com.freetipscentral.domain;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name ="books")
@XmlAccessorType(XmlAccessType.FIELD)
public class Books {
  
  @XmlElement(name="book")
  List<Book> books;
  int totalPrice;
  
  public List<Book> getBooks() {
    return books;
  }
  public void setBooks(List<Book> books) {
    this.books = books;
  }
  public int getTotalPrice() {
    return totalPrice;
  }
  public void setTotalPrice(int totalPrice) {
    this.totalPrice = totalPrice;
  }
  
  
}

BookCreator.java

package com.freetipscentral.utility;

import java.util.ArrayList;
import java.util.List;

import com.freetipscentral.domain.Book;

public class BookCreator {
  
  public static List<Book> getBooks() {
    List<Book> books = new ArrayList<Book>();
    Book book1 = new Book("Head First Java",1);
    Book book2 = new Book("Head First Design Pattern",2);
    books.add(book1);
    books.add(book2);
    return books;
  }

}

Here is the input Body

<books>
  <book>
  <name>The law of Karma</name>
  <serialNumber>3</serialNumber>
  </book>
  <book>
  <name>Freedom at midnight</name>
  <serialNumber>4</serialNumber>
  </book>
  <book>
  <name>Deep Work</name>
  <serialNumber>5</serialNumber>
  </book>
  <totalPrice>100</totalPrice>
</books>

 

 

Input Header

Content-Type  application/xml

Here is the Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<books>
    <book>
        <name>Head First Java</name>
        <serialNumber>1</serialNumber>
    </book>
    <book>
        <name>Head First Design Pattern</name>
        <serialNumber>2</serialNumber>
    </book>
    <book>
        <name>The law of Karma</name>
        <serialNumber>3</serialNumber>
    </book>
    <book>
        <name>Freedom at midnight</name>
        <serialNumber>4</serialNumber>
    </book>
    <book>
        <name>Deep Work</name>
        <serialNumber>5</serialNumber>
    </book>
</books>

Here is the Video version of this tutorial

 

How To Resolve 400 Bad Request While Posting XML Data to REST Service

While writing a REST service to accept XML  as the POST data you could run into the following problem while submitting XML data – HTTP Status 400 – Bad Request.  If you see https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html you will see that 400 Bad request means Server is not able to serve the request due to malformed request from the client.  You can find example of how to post xml data to a REST service here.

In that example there was a Book class which was annotated as follows –
@XmlRootElement (name = “book”)
public class Book {

}

The input xml sent should be similar to following –

<book>
  <name>My Experiments With Truth</name>
  <serialNumber>3</serialNumber>
</book>

When the XML data is submitted it is converted to Book Object.  Here are some scenarios when you may get 400 bad request.

  1. If the xml root element is not <book>.  For example if the root element is <Book> it will throw bad request exception.  The reason is the mapping on the Book class expected <book> to be the root element.
  2. You may remove the (name = “book”> from the Book class and still it will work for <book>.  The reason is small case element name for the class name will work.
  3. If you want to use <Book> or any other element name such as <Novel> then you need to add it as attribute in the Book class annotation.  For example you can annotate the book class as follows

@XmlRootElement (name = “Book”)
public class Book {

}

In this case REST service can be called with following request data.

<Book>
  <name>My Experiments With Truth</name>
  <serialNumber>3</serialNumber>
</Book>

 

or

@XmlRootElement (name = “Novel”)
public class Book {

}

The the following XML should be sent.

<Novel>
  <name>My Experiments With Truth</name>
  <serialNumber>3</serialNumber>
</Novel>