What Are Default Methods in Java 8

Default methods were added in Java 8 to allow adding of new methods to interface without breaking existing implementing classes.  Using default methods we can add functionality to existing classes which implemented a common interface.

Note – All the Java source files in this project can be found at https://github.com/freetipscentral/java8-defaultmethod

Here is one example of Default method

Lets assume that we have a GenericRemote interface and two classes which implement the interface.

package com.freetipscentral.defaultmethod;

public interface GenericRemote {
  
  public void startDevice();
}

 

package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
}
package com.freetipscentral.defaultmethod;

public class MusicSystemRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("Music System Started");
  }
}

In the above example you can see that two classes TVRemote and MusicSystemRemote implementing the interface GenericRemote hence they also implement the method startDevice().

Now consider the situation where in you need to add one more method stopDevice() to the interface GenericRemote interface.

Before Java 8 as soon as you add that method to the GenericRemote interface all the classes below will start having compilation problems.  You can solve the compilation problems by implementing the method in all the classes which implement this interface.  Same happens in Java 8 also.

But Java 8 has a more elegant solution for this.  That is called Default method.  Default method are a way to add a default implementation of the interface method on the interface itself.  That way if the interface undergoes changes after it has been implemented by many classes, those classes will not have compilation errors.

How to Add a Default Implementation Method

To add a default implementation add the keyword default at the start of the method signature and then implement the method.  Here is how the above implementations will look like after adding the default method.  Notice how the implementing classes have not undergone any changes.

package com.freetipscentral.defaultmethod;

public interface GenericRemote {
 
 public void startDevice();
 
 default public void stopDevice() {
 System.out.println("Default Stop Device");
 }
}
package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
}
package com.freetipscentral.defaultmethod;

public class MusicSystemRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("Music System Started");
  }
}

Do The Implementing Classes Have Choice to Overriding Default Methods

Yes implementing classes can always override the default method and add their own implementation.  That way they can have the best of both worlds.

For example TVRemote class can always override the default implementation as below.

package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
  
  @Override
  public void stopDevice() {
    System.out.println("TV Stopped");
  }
}

 

Why Default methods were added to Java 8

Default methods were added to Java so that backwards compatibility could be maintained with older collection framework.  One of the new method added to the Collection interface is forEach.  forEach is an internal iterator which has been  added to Iterable interface in Java 8.  Collection interface extends Iterable interface.  This method helps in iterating through the objects in the collection.  For example consider the following example –

Here is what is being done in the code.

  1. Create a list of Students.
  2. Add Student objects to the list
  3. Iterate through the list and print the students.

If you notice carefully we are using forEach which is an internal iterator.  Since this is new addition to the Collection framework  all the previously written codes (running in millions of lines) which used Collection interface such as List or Set would have failed.  Hence Java 8 added the default method so that the code remains backward compatible.  If you see the Oracle documentation on Iterable interface you will see that forEach is a default method.  Here is the link to Oracle documentation on Iterable interface.

package com.freetipscentral.defaultmethod;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import com.freetipscentral.defaultmethod.domain.Student;

public class StudentManager {
  public static void main(String args[]) {
    List<Student> students = new ArrayList<Student>();
    
    //Create Students and add to list
    Student student1 = new Student("Karen",1);
    Student student2 = new Student("Rahul",2);
    students.add(student1);
    students.add(student2);
    
    //Iterate through the list and print the student objects
    students.forEach(new Consumer<Student>() {
      public void accept(Student s) {
        System.out.println(s);
      }
    });
  }
}

What happens when a class inherits two interfaces with default methods with same name

If a class implements two interfaces with same default method name then it will cause compile error in the class.  The solution is to implement the default method in the class.

What Happens When an Interface Extends Another Interface With Default Method

If an interface extends another interface which has default method then the interface and its implementing classes also have access to the default method.

However the child interface can also make it abstract.  It the child interface makes it abstract then the implementing classes of the child interface have to implement the method.  Here is an example of how child interface can make the default method abstract.  All classes implementing MobileRemote need to implement stopDevice() method.

package com.freetipscentral.defaultmethod;

public interface MobileRemote extends GenericRemote {
  public void stopDevice();
}

The child interface can also override the default interface with its own default method.  In this case the implementing classes of the child interface can use the default method of the child interface.   Here is an example of how child interface can override the default method.

package com.freetipscentral.defaultmethod;

public interface CarRemote extends GenericRemote {
  default public void stopDevice() {
    System.out.println("Stop the Car");
  }
}

 

 

Lambda Expression Tutorial

Lambda expressions are one of the new additions to Java 8.  It is also one of the most talked about and exiting features of Java 8.  We will cover what exactly are Lambda expressions and some examples in this article.

What are Lambda Expressions?

Lambda expressions are a way use a expression to represent function calls which are usually on anonymous classes.  Usually anonymous inner classes have just one method and extend some interface.  The entire purpose of writing anonymous inner classes is to implement a single method.  Lambda expressions can help us reduce the code written around anonymous inner classes by reducing to to a single statement.

Here is a simple example of Lambda expression –

( i ) -> (System.out.println(i));

Let us see an example.

In the following class following is happening –

Let us assume that you want to sort a array list of Integers using a anonymous class which implements Comparator interface.  Here are the steps –

  1. Initialize a ArrayList of integers. (Line 10)
  2. We want to sort the numbers in the list so we take help of anonymous class which implements Comparator interface (Line 11).  There is only one method inside it called compare which contains the logic for comparison.  We call the compare method in the instance of the anonymous class (Line 12).  This method compares the values in the list and returns a sorted list.
  3. Once the list is sorted we print the list (Line 17 – 20).
package com.freetipscentral.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class LambdaExample1 {
  public static void main(String args[]) {
    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,20);
    Collections.sort(numbers, new Comparator<Integer>(){
      public int compare(Integer i1, Integer i2){
        return i1.compareTo(i2);
      }
    });
    
    for(Integer i : numbers) {
      System.out.println(i);
    }
  }
}

Here is the output of above code –

1
2
3
4
5
6
7
8
9
20

Lambda Expression For the Above Code

The above code can also be written using Lambda expressions.  Once we translate the Anonymous class to Lambda expression here is how the class looks like –

package com.freetipscentral.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class LambdaExample1 {
  public static void main(String args[]) {
    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,20);
    Collections.sort(numbers, (Integer i1, Integer i2) -> i1.compareTo(i2));
    
    for(Integer i : numbers) {
      System.out.println(i);
    }
  }
}

In the code above the actual Lambda expression is only the following code.

(Integer i1, Integer i2) -> i1.compareTo(i2)

If you run the above class the output would be same as above.  However there are two things which have happened in the code. Firstly the number of lines of code has decreased and secondly code is also simpler to understand.  If you do not find it east then do not worry.  I will explain how to do it.

Steps to reduce anonymous class function call to Lambda expressions

There are only three conceptual things you need to take care while converting a function call to Lambda expression.

  1. You only need the parameter list on the left and method body on the right.
  2. Parameter and the method body will be separated by ->
  3. Remove everything else including name of the method and return type.  They are all inferred.  The return statement is also not needed as that is inferred.

Let us see the above steps in the following example where we will convert the function call to Lambda expression.

Collections.sort(numbers, new Comparator<Integer>(){
  public int compare(Integer i1, Integer i2){
    return i1.compareTo(i2);
  }
});

The anonymous class starts at new Comparator ...

Remove from new till end of compare.  You will have the following code.

Collections.sort(numbers, (Integer i1, Integer i2){
    return i1.compareTo(i2);
  }
});

Replace { with -> at the end of the first line. Also remove the return keyword at the beginning of second line as that is implicit.

Collections.sort(numbers, (Integer i1, Integer i2) ->
    i1.compareTo(i2);
  }
});

Last step is to remove the braces for the function ending and the anonymous class at the end.  After you remove here is the code.

Replace { with -> at the end of the first line.

Collections.sort(numbers, (Integer i1, Integer i2) ->
  i1.compareTo(i2);
);

Here is the code after formatting.

Collections.sort(numbers, (Integer i1, Integer i2) -> i1.compareTo(i2);
);

 

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