Wednesday 8 October 2014

Examples of Comparable, Comparator, equals() & hashCode()

We can discuss the use of Comparable, Comparator interfaces & equals(), hashCode() methods by using some problem description.

In Java, there is an utility called Collections to perform most of the required operations on collection framework classes.
One of the most frequently used operation is Sorting. We can do the sorting by using Collections.sort() method.
Collections.sort() method has the following two forms.

sort(List list) - Sorts the specified list into ascending order, according to the natural ordering of its elements.
sort(List list, Comparator c) - Sorts the specified list according to the order induced by the specified comparator.

Comparable and Comparator are two interfaces provided by Java Core API. From their names, we can tell they may be used for comparing stuff in some way. But what exactly are they and what is the difference between them?

Comparable:Comparable is implemented by a class in order to be able to comparing object of itself with some other objects. The class itself must implement the interface in order to be able to compare its instance(s). The method required for implementation is compareTo().
Objects which implement Comparable in java can be used as keys in a SortedMap like TreeMap or SortedSet like TreeSet without implementing any other interface.

Comparator:
Class whose objects to be sorted do not need to implement this interface. Some third class can implement this interface to sort.
Using Comparator interface, we can write different sorting based on different attributes of objects to be sorted.You can use anonymous comparator to compare at particular line of code.


Parameter
Comparable
Comparator
Sorting logic
Sorting logic must be in same class whose objects are being sorted. Hence this is called natural ordering of objects
Sorting logic is in separate class. Hence we can write different sorting based on different attributes of objects to be sorted. E.g. Sorting using id,name etc.
Implementation
Class whose objects to be sorted must implement this interface.e.g Country class needs to implement comparable to collection of country object by id
Class whose objects to be sorted do not need to implement this interface.Some other class can implement this interface. E.g.-CountrySortByIdComparator class can implement Comparator interface to sort collection of country object by id

Sorting method
int compareTo(Object o1)
This method compares this object with o1 object and returns a integer.Its value has following meaning
1. positive – this object is greater than o1
2. zero – this object equals to o1
3. negative – this object is less than o1
int compare(Object o1,Object o2)
This method compares o1 and o2 objects. and returns a integer.Its value has following meaning.
1. positive – o1 is greater than o2
2. zero – o1 equals to o2
3. negative – o1 is less than o1
Calling method
Collections.sort(List)
Here objects will be sorted on the basis of CompareTo method
Collections.sort(List, Comparator)
Here objects will be sorted on the basis of Compare method in Comparator
Package
Java.lang.Comparable

Java.util.Comparator

equals() & hashCode() methods: In Java every object has access to equals() & hashCode() methods, since these are available in java.lang.Object class & Object class is super class by default for all the classes. The main intention of these methods are to compare the given two or more objects and identify their equality.

The default implementation of equals() method in Object class simply checks if two object references x and y refer to the same object. i.e. It checks if x == y. This particular comparison is also known as "shallow comparison".


These two methods have significant relationship with each other. If we want to override any one of the methods, need to override both the methods. We will discuss why do we need to override both, otherwise what is the impact.


The equals() method must exhibit the following properties:
  1. Symmetry: For two references, a and b, a.equals(b) if and only if b.equals(a)
  2. Reflexivity: For all non-null references, a.equals(a)
  3. Transitivity: If a.equals(b) and b.equals(c), then a.equals(c)
  4. Consistency with hashCode(): Two equal objects must have the same hashCode() value

Why do we need to override equals() method: An object might have many number of variables, but we may need to consider only few variables into consideration while comparing the objects.
Suppose, customer landed on some eCommerce application and would like buy some article. Article may have many number of properties such as name, capacity, cost, availability, seller_name, seller_location, delivery_date..etc. But while coming to comparison, customer may consider name, price & delivery_date.
Hence, it require to apply equals() methods to lookup only these properties while determining equality. 

Why to override hashCode() method: hashCode() method is used to get a unique integer for given object. This integer is used for determining the bucket location, when this object needs to be stored in some HashTable, HashMap like data structure. By default, Object’s hashCode() method returns an integer representation of memory address where object is stored.
The hashCode() method of objects is used when we insert them into a HashTable, HashMap or HashSet. More about hastables on Wikipedia.org for reference.
To insert any entry in map data structure, we need both key and value. If both key and values are user define data types, the hashCode() of the key will be determine where to store the object internally. When require to lookup the object from the map also, the hash code of the key will be determine where to search for the object.
The hash code only points to a certain "area" (or list, bucket etc) internally. Since different key objects could potentially have the same hash code, the hash code itself is no guarantee that the right key is found. The HashTable then iterates this area (all keys with the same hash code) and uses the key's equals() method to find the right key. Once the right key is found, the object stored for that key is returned.
So, as we can see, a combination of the hashCode() and equals() methods are used when storing and when looking up objects in a HashTable.

NOTES:
1.       Always use same attributes of an object to generate hashCode() and equals() both. As in our case, we have used employee id.
2.       equals() must be consistent (if the objects are not modified, then it must keep returning the same value).
3.       Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().
4.       If you override one, then you should override the other.

Problem Statement:
There are 2 travel companies who have buses travelling from dest A to dest B. they want to merge their buses timetable and produce it to the customer so that they can find out which bus is effective for them and choose bus accordingly(o/p).

They will provide a text file having the I/P as shown above and we need to give O/P as shown above.

Conditions:
1) If the bus travel time is greater than 1hr then it should not be displayed.
2) If the both the travel agency having same time of dept and arrival then we need to show only volvo travel time and ignore BMW.
3) we need to format O/P as
a) if busA starts at 10 and arrives at 11, if busB starts at 10:05 and arrives at 11, then busB has to come before busA.
b) if busA starts late and arrives before busB,then busA has to come before busB.
c) if busA starts at same time as busB but reaches before,then busA has to come before busB.

Input file:


volvo 10:10 11:05
volvo 10:15 11:05
volvo 11:00 12:15
volvo 11:50 12:50
volvo 12:00 12:45
BMW 10:05 11:05 
BMW 10:10 11:05
BMW 10:50 11:45
volvo 10:50 11:45
BMW 11:05 12:15

Output:
volvo 10:15 11:05
volvo 10:10 11:05
BMW 10:05 11:05
volvo 10:50 11:45
volvo 12:00 12:45
volvo 11:50 12:50

BusInfoVO: Its a Data transfer object which holds the information of a bus.
package com.exer.files.vo;

import java.io.Serializable;
import java.util.Date;

public class BusInfoVO implements Comparable<BusInfoVO>, Serializable {
 
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 
 private String busType;

 private Date startTime;

 private Date endTime;

 private transient Long duration;
 
 public String getBusType() {
  return busType;
 }

 public void setBusType(String busType) {
  this.busType = busType;
 }

 public Date getStartTime() {
  return startTime;
 }

 public void setStartTime(Date startTime) {
  this.startTime = startTime;
 }

 public Date getEndTime() {
  return endTime;
 }

 public void setEndTime(Date endTime) {
  this.endTime = endTime;
 }

 public Long getDuration() {
  return duration;
 }

 public void setDuration(Long duration) {
  this.duration = duration;
 }

 @Override
 public int compareTo(BusInfoVO busInfo) {
  
  if((this.getStartTime().equals(busInfo.getStartTime())) && (this.getEndTime().equals(busInfo.getEndTime()))) {
   return 0;
  } if((this.getStartTime().equals(busInfo.getStartTime())) || (this.getEndTime().equals(busInfo.getEndTime()))) {
   return this.getDuration() < busInfo.getDuration() ? -1 : 1;
  } else if((this.getStartTime().after(busInfo.getStartTime())) && (this.getEndTime().before(busInfo.getEndTime()))) {
   return -1;
  } else if(this.getStartTime().before(busInfo.getStartTime())) {
   return -1;
  }
  return 1;
 }
 
 @Override
 public boolean equals(Object busInfo) {
  boolean result = false;
  
  if (busInfo == null || (this.getClass() != busInfo.getClass())) {
   return result;
  }
  
  BusInfoVO other = (BusInfoVO) busInfo;
  if((this.getStartTime().equals(other.getStartTime())) && (this.getEndTime().equals(other.getEndTime()))) {
   return true;
  }
  
  return result;
 }
 
 @Override
 public int hashCode() {
  int hash = 10;
  hash = hash + this.getStartTime().getHours() + this.getStartTime().getMinutes();
  hash = hash + this.getEndTime().getHours() + this.getEndTime().getMinutes();
  return hash;
 }

}


Here BusInfoVO class implementing Comparable interface and overrides compareTo() method.

FilesReader.java: Where data can be read and processed as expected output.
package com.exe.files.reader;

import java.io.File;
import java.io.FileNotFoundException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
import java.util.TreeSet;

import com.exer.files.vo.BusInfoVO;

public class FilesReader {

 private static DateFormat dateFormat = new SimpleDateFormat("HH:mm");
 
 private List<BusInfoVO> busInfoVOList;

 public List<BusInfoVO> getBusInfoVOList(String path) {
  if(path != null) {
   File folder = new File(path);
   File[] listOfFiles = folder.listFiles(); 
   busInfoVOList = new ArrayList<BusInfoVO>();
   for (int i = 0; i < listOfFiles.length; i++) {
    try (Scanner scanner = new Scanner(listOfFiles[i])) {
     while (scanner.hasNextLine()) {
      String[] info = scanner.nextLine().toString().split(" ");
      if (info != null && info.length > 0) {
       BusInfoVO vo = new BusInfoVO();
       vo.setBusType(info[0]);
       Date startTime = dateFormat.parse(info[1]);
       Date endTime = dateFormat.parse(info[2]);
       vo.setStartTime(startTime);
       vo.setEndTime(endTime);
       vo.setDuration((endTime.getTime() - startTime.getTime()) / (60 * 1000)); // In minutes.
       if(vo.getDuration() <= 60) {
        busInfoVOList.add(vo);
       }
      }
     }
    } catch(ParseException | FileNotFoundException exp) {
     exp.printStackTrace();
    }
   }
   Collections.sort(busInfoVOList, new Comparator<BusInfoVO>() {

    @Override
    public int compare(BusInfoVO o1, BusInfoVO o2) {
     return o2.getBusType().compareTo(o1.getBusType());
    }
   });
   return busInfoVOList;
  }
  
  return null;
 }
 
 public static void main(String[] args) throws ParseException, FileNotFoundException {
  String path = "D:\\PARAMESH\\FILES";
  FilesReader reader = new FilesReader();
  List<BusInfoVO> list = reader.getBusInfoVOList(path);
  TreeSet<BusInfoVO> set = new TreeSet<BusInfoVO>();
  for(BusInfoVO vo : list) {
   set.add(vo);
  }

  for(BusInfoVO vo : set) {
   System.out.println(vo.getBusType() + " " + dateFormat.format(vo.getStartTime()) + " " + dateFormat.format(vo.getEndTime()));
  }
 }
}

Here, we used(@ L 50) "sort(List<T> list, Comparator c)" method to sort the list based on the name field of BusInfoVO.

While adding to the set.add(vo) (@L 69), its looks for the equals() method definition available in BusInfoVO class and compares the given object with all existing objects in the set.
If equals returns : true - Will add the given object to the set.
                             false - Will not add the given object to the set.
Also, when we add the elements in TreeSet, it internally calls compareTo() method available in the given for sorting.

Thursday 13 March 2014

Best approach for formatting date in java


The most common approach to format the date as required by using SimpleDateFormat.


This approach causes problems when multiple threads access the same instance of the class variable, due to lack of synchronization.


The below are the most frequent exceptions will occurs:
  • java.lang.NumberFormatException
  • java.lang.ArrayIndexOutOfBoundsException

There are two approaches to handle these exceptions in Multi-threading environment.
  1. By using ThreadLocal<SimpleDateFormat>: ThreadLocal is a best appraoch to implement Per Thread Singleton classes or per thread context information.
  2. FastDateFormat.getInstance(): FastDateFormat is available in commons-lang-version.jar. it has several overloaded methods of getInstance() to provide the date format for Thread-safe environment. Please find the API documents here.

Sample code snippet by using SimpleDateFormat:
package com.samples;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample {
 
 private static DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
 
 public static void main(String[] args) {
  Date currentDate = new Date();
  System.out.println("Current Time: " + dateFormat.format(currentDate));
 }

}



Sample code snippet by using ThreadLocal:
package com.samples;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadLocalDateFormatExample {

 private static ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {
  protected DateFormat initialValue() {
   return new SimpleDateFormat("MM/dd/yy");
  }
 };
 
 public static void main(String[] args) {
  Date currentDate = new Date();
  System.out.println("Current Time: " + dateFormat.get().format(currentDate));
 }

}


Sample code snippet by using FastDateFormat:
package com.samples;

import java.util.Date;

import org.apache.commons.lang.time.FastDateFormat;

public class FastDateFormatExample {

 private static final FastDateFormat dateFormat = FastDateFormat.getInstance("dd-MM-yyyy");
 
 public static void main(String[] args) {
  Date currentDate = new Date();
  System.out.println("Current Time: " + dateFormat.format(currentDate));
 }
}

Hence, the best approach is to format the date isby using FastDateFormat if your project has commons-lang.jar dependency, otherwise can use Threadlocal approach.

Wednesday 5 March 2014

Unix basic commands

Below are the few basic Unix commands which will be more useful for Java developers who are working in Unix environment.

List all users:
cat /etc/passwd |grep "/home" |cut -d: -f1
awk -F":" '{ print "username: " $1 "\t\tuid:" $3 }' /etc/passwd

The above commands will list all the users in the system.

Some Basic commands:
cd path - change directory.
mv path1/filename1 path2/filename2 - Move files from one directory to another directory.
ls [options]- list the file names.
ll [options]- list the file names with permissions and size.
cp path/filename1 path2/filename2 - Copy files from one directory to another directory.
cat filename - To print the content of the file.
diff filenmae1 filename2 - To view the differences between two files.
./filename.sh - To run sh files. This is mostly used for executing shell scripts and server stop start.
view filename - To view the content of the file.
vi filename - To view and update the file.
top - To check the CPU performance and utilization.
df - To check the disk space utilized.

vi & view editor commands:
----------------------------
When a opened a file with vi/view command, the file will open in command mode as default. To make changes in the files needs bring to "Insert Mode".
i/<Ins> - insert text before cursor, until <Esc> hit. Also called "Insert Mode".
I - insert text at beginning of current line, until <Esc> hit
<Esc> - Change to "Command Mode".

:w - saves the current file without quitting
:# - move to line #
:$ - move to last line of file
?string - Search backward for string
/string - Search forward for string
n - move to next occurrence of search string
N - move to next occurrence of search string in opposite direction
<Esc>:w! - Saves the file
<Esc>:q! - Quit editing, no save

Create a .jar file:
$ jar -cvf <file_namer.jar> <class_file_path>

To work with above command, first we need to change the directory to JDK installed bin directory and execute the command.

Ex:
$ /opt/WebSphere7/AppServer/java/bin/jar -cvf calculator.jar com/calc/Calculator.class
$ /opt/WebSphere7/AppServer/java/bin/jar -cvf ibank.jar com/calc/*.class

The second command is useful when there are multiple class to be include in a jar. the path /opt/WebSphere7/AppServer/java/bin is a JDK installed path from whepsher server.


Update a .jar file:
jar -uvf <file_namer.jar> <class_file_path>

Ex:
$ /opt/WebSphere7/AppServer/java/bin/jar -uvf calculator.jar com/calc/Calculator.class
$ /opt/WebSphere7/AppServer/java/bin/jar -uvf calculator.jar com/calc/*.class

Unzar a .jar file:
$ jar -xvf <file_namer.jar>

Ex:
$ /opt/WebSphere7/AppServer/java/bin/jar -xvf calculator.jar
Once the above command executed, we will get the class files in unix files system. So first we need to change the directory where we need the files to be located and provide bin full path while executing the command.
If we not change the directory and executed from JDK installed path, all extracted files will be placed in JDK installed path.

Find a Class file in .jar file:
grep classname *.jar

Ex:
grep com/calc/Calculator.class *.jar
grep Ibank.class *.jar

To Know the package exactly:
$ /opt/WebSphere7/AppServer/java/bin/jar -tvf calculator.jar|grep Calculator*

Check HTTP Server status:
$ ps -efw|grep httpd

File system size:
When we are facing with file system space issue and not able to find which directory occupies more memory, use the below command.

du -sm *| sort -nr | head -15
du -sh * | sort -nr | more

To transfer tar files from one IP to another IP:
Login to the IP address, where the file is available and execute the below command.
$ /usr/local/openssh/bin/scp <path>/<file_name>  <userid>@<ip_address>:/tmp/


Thursday 30 January 2014

Spring Annotations

Introduction:

In Spring, XML based configurations is the most popular configuration style. Spring uses annotations as an alternative to XML for declarative configuration.

To make annotations and work in spring, use the <context:component-scan> tag in spring bean configuration file. So that spring will scan and find out the beans and register in the Spring Container.

Syntax:

Ex:

Note: If it requires adding multiple packages to scan, use comma separator.

Auto Components Scan Annotation Types:
In Spring, there are 4 types of auto components scan annotation types
  • @Component – Indicates an auto scan component.
  • @Repository – Indicates DAO component in the persistence layer.
  • @Service – Indicates a Service component in the business layer.
  • @Controller – Indicates a controller component in the presentation layer.

<context:annotation-config> is used to activate annotations in beans already registered in the application context.

Component-scan vs annotation-config:
<context:annotation-config>: Only registers 4 BeanPostProcessors that are part of the Spring Framework and have specific configuration objectives.
  • CommonAnnotationBeanPostProcessor: Recognizes and processes the JSR 250 common annotations (@PostConstruct, @PreDestroy, @Resource).
  • AutowiredAnnotationBeanPostProcessor: Recognizes the Autowired related annotations (@Autowired, @Value, @Inject, @Qualifier, etc)
  • RequiredAnnotationBeanPostProcessor: Recognizes the @Required annotation
  • PersistenceAnnotationBeanPostProcessor: Recognizes the @PersistenceUnit and @PersistenceContext annotations (related to JPA).
All of these annotations are typically placed either on a class field, constructor or method. <context:component-scan>: is a super set of the <context:annotation-config> tag. It registers the same bean post processors and also will perform component scanning. It looks for classes in the given base-package that are annotated with a category of annotations (@Component, @Repository, @Controller, etc). The purpose of using is to provide an alternative way to 'discover' Spring components other than using XML.

Spring related Annotations:

Below are the few important spring related annotations and their package.
Spring Annotation
Package
@Controller
org.springframework.stereotype.Controller
@RequestMapping
org.springframework.web.bind.annotation.RequestMapping
@RequestParam
org.springframework.web.bind.annotation.RequestParam
@PathVariable
org.springframework.web.bind.annotation.PathVariable
@ModelAttribute
org.springframework.web.bind.annotation.ModelAttribute
@SessionAttributes
org.springframework.web.bind.annotation.SessionAttributes
@PreAuthorize
org.springframework.security.access.prepost.PreAuthorize

@Controller Annotation:

The @Controller annotation indicates that a particular class serves the role of a controller. The controller class is no longer need to extends any of base controllers. When we @Controller annotation, its mandatory to use @RequestMapping annotation. This annotation is used to map a particular http/https request.

@RequestMapping Annotation:

This annotation can be used at both class level and method level. In case of multi-action controller, it’s recommended to use this annotation at method level and also at class level if required.

Syntax at class level: @RequestMapping("/") 
Syntax at method level: @RequestMapping(value = “/”, method = RequestMethod.[GET/POST]) 

We can use wildcard characters like * for path pattern matching. 

Simple scenario:
@Controller
@RequestMapping("/blogspot")
public class blogspotController {

 @RequestMapping(value="/properties")
 public String findAllProperties(){

 }
}
Testing URL: /blogspot/properties

Request parameter binding:
@RequestMapping(value="/properties")
public String findByProperty(@RequestParam("propertyId") String propertyId){
  
}
Testing URL: /blogspot/properties?propertyId =<some_id>

Extracting path variables:
@RequestMapping(value="/blogspot/{propertyId}")
public String findByProperty(@PathVariable String paropertyId){

}
(OR)
@RequestMapping(value="/blogspot/{propertyId}")
public String findByProperty(@PathVariable("propertyId") String somePropertyId){

}
Testing URL: /blogspot/properties/propertyId/23

Extracting multiple path variables:
@RequestMapping(value="/properties/{propertyId}/owner/{ownerId}")
public String findByProperty( @PathVariable String propertyId,  @PathVariable String ownerId){

}
Testing URL: /blogspot/ properties/23/owner/39

Extracting regular expressions:
@RequestMapping(value="/{textualPart:[a-z-]+}.{numericPart:[\\d]+}")
public String regularExpression( @PathVariable String textualPart, @PathVariable String numericPart){

}
Testing URL: /blogspot/text_chars.123

@RequestParam Annotation:

It’s a method argument annotation. This @RequestParam annotation can be used for getting the parameters from the request(query parameters). The scope of the variable passed is method scope. Syntax:
@RequestParam(value = “requestParam”, required = true/false, defaultValue = "defaultVal") dataTye variableName)
Ex:
public void printPageInfo(@RequestParam(value = "pageNumber", required = false, defaultValue = "1")  Integer pageNumber)

@PathVariable Annotation:

It’s a method argument annotation. The @PathVariable annotation can be used for getting the value of URI template variable. Syntax:
@PathVariable("pathVarName") dataTyep variableName)
Ex: If we want to create a controller that would allow users to see view pages by using a URL as below http://parameshk.blogspot.in/search/label/Java - display details for java http://parameshk.blogspot.in/search/label/Spring - display details for spring
@Controller
@RequestMapping("/search")
public class ShowPagesController {
    @RequestMapping("/label/{labelName}") // Handle any request of the form "/label/XXXXX"
    public String showProduct(Model model, @PathVariable("labelName") String labelName) {
    }
}

@ModelAttribute Annotation:

It supports RequestMapping annotated handler classes. It binds a method parameter or method return value to a named model attribute that exposed to a web view. Uses of @ModelAttribute: Useful to read data from an existing model by assigning it to handler method parameters. If a view/jsp want to populate some values while onload, we can inject the data to jsp by using this annotation. Ex: Below is the code snippet, which binds Employee object to a view page. Code snippet in controller:
@RequestMapping(value="/property-details")  
public ModelAndView processPerson(@ModelAttribute Property prop) {  
    ModelAndView modelAndView = new ModelAndView();  
    modelAndView.setViewName("property-details");  
    modelAndView.addObject("property", prop);  
    return modelAndView;  
}
Code snippet in jsp/view page:
Property Details:
Property Name: ${ property.name}
Property Location: ${ property.location}
Property Owner: ${ property.owner}

@ SessionAttributes Annotation:

The @SessionAttributes annotation is used to store the model object in the session. It is used on the Controller class level to declare used session attributes. All Model attributes having names or types defined in this annotation will be automatically persisted and restored between the subsequent requests. It’s a very small declaration instead of using HttpSession's getAttribute() & setAttribute() calls. Model attributes are persisted at the end of request handling by AnnotationMethodHandlerAdapter, after calling the handler method responsible for request handling and after determining the ModelAndView for the response. Their names in Model are used as their names in the persistent storage. Ex: @SessionAttributes("form") will trigger persisting Model attribute named "form" as HttpSession attribute named "form". Persisted Model attributes will be removed only when SessionStatus.setComplete() method called in handler methods. Ex:
@Controller
@RequestMapping(value="/dashboard", method=RequestMethod.POST)
@SessionAttributes("property")
public class LoginController {
    @RequestMapping(value="/authenticate",method=RequestMethod.POST)
    public String authenticate(@RequestParam String propertyId, Model model){
        Property property = new Property();
        property.setPropertyId(propertyId);
        property.setName("PPB_1");
        property.setLocation("USA");
        model.addAttribute("property", property);
        return "xxxxx";
    }
}
Note: To store multiple objects in @SessionAttributes use comma separator.

RESTful Web Service - JAX-RS Annotations:

  • Jersey, the reference implementation of JAX-RS, implements support for the annotations defined in JSR 311, making it easy for developers to build RESTful web services by using the Java programming language.
  • REST is an architectural style which is based on web-standards and the HTTP protocol.
  • In REST based architecture everything is a resource. A resource is accessed via a common interface based on the HTTP standard methods.
  • In a REST based architecture you typically have a REST server which provides access to the resources and a REST client which accesses and modify the REST resources.
  • Every resource should support the HTTP common operations. Resources are identified by global IDs (which are typically URIs).
  • REST allows that resources have different representations, e.g. text, xml, json etc. The rest client can ask for specific representation via the HTTP protocol (content negotiation).
JAX-RS Annotation
Package
@Path
javax.ws.rs.Path
@Produces
javax.ws.rs.Produces
@Consumes
javax.ws.rs.Consumes
@GET
javax.ws.rs.GET
@POST
javax.ws.rs.POST
@PUT
javax.ws.rs.PUT
@DELETE
javax.ws.rs.DELETE
@FormParam
javax.ws.rs.FormParam
@PathParam
javax.ws.rs.PathParam
@QueryParam
javax.ws.rs.QueryParam

@Path Annotation:

It’s a both class & method level annotation. This identifies the URI path template to which the resource responds. The @Path annotation's value is a partial URI path template relative to the base URI of the server on which the resource is deployed, the context root of the WAR, and the URL pattern to which the Jersey helper servlet responds.

Syntax:
    @Path("/uri")

The @Path annotation is not limited to simple path expressions. We can also have the ability to insert regular expressions into @Path's value.

Syntax: @Path (“uri/{variable[:regular-expression]}”)
Ex:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

@Path("/properties")
public class UserRestService {

 @GET
 public Response getProperties() {
  //TODO provide method body
 }
 //Target Url: /properties

 @GET
 @Path("/ppb")
 public Response getPropertyPPB() {
  //TODO provide method body
 }
 //Target Url: /properties/ppb
 
 @GET
 @Path("{name}")
 public Response getPropertyByName(@PathParam("name") String name) {
  //TODO provide method body
 }
 //Target Url: /properties/abcdefg

 @GET
 @Path("{id : \\d+}") //id is regular expression which accepts only numbers
 public Response getPropertyById(@PathParam("id") String id) {
  //TODO provide method body
 }
 //Target Url: /properties/1234

 @GET
 @Path("/propertyname/{propertyname : [a-zA-Z][a-zA-Z_0-9]+}")
 public Response getPropertyByPropertyName(@PathParam("propertyname") String propertyname) {
  //TODO provide method body
 }
 //Target Url: /properties/propertyname/myproperty123

}

@Consumes Annotation:

The @Consumes annotation is used to specify which MIME media types of representations, a resource can accept/ consume from the client. @Consumes annotation can be applied at both the class and method levels. If it’s applied at class level, by default all the methods will accept the same MIME type. If it’s applied at the method level, overrides the class level annotation if applied. The possible MIME types which can be used for this annotation can be available in the class javax.ws.rs.core.MediaType.

Syntax: 
   @Consumes(MediaType.XXX) @Consumes({MediaType.XXX, MediaType.YYY, …})

@Produces Annotation:

The @Produces annotation is used to specify the MIME media types of representations a resource can produce and send back to the client. @Produces annotation can be applied at both the class and method levels. If it’s applied at class level, by default all the methods will accept the same MIME type. If it’s applied at the method level, overrides the class level annotation if applied. The possible MIME types which can be used for this annotation can be available in the class javax.ws.rs.core.MediaType.

Syntax: 
    @Produces (MediaType.XXX) @Produces ({MediaType.XXX, MediaType.YYY, …})

@GET, @PUT, @POST, @DELETE & @HEAD Annotations:

@GET, @PUT, @POST, @DELETE and @HEAD are resource method designator annotations defined by JAX-RS and which correspond to the similarly named HTTP methods. In the example above, the annotated Java method will process HTTP GET requests. The behavior of a resource is determined by which of the HTTP methods the resource is responding to.
  • GET defines a reading access of the resource without side-effects. The resource is never changed via a GET request, e.g. the request has no side effects (idempotent).
  • PUT creates a new resource, must also be idempotent.
  • DELETE removes the resources. The operations are idempotent, they can get repeated without leading to different results.
  • POST updates an existing resource or creates a new resource.

@QueryParam Annotation:

Binds the value of a HTTP query parameter to a resource method parameter or resource class field or resource class bean property. A default value can be specified using the @DefaultValue annotation. Syntax:
@QuaryParam(“param1”) @DefaultValue(“defaultVal”) datatype varName
Ex:
@QuaryParam(“param1”) @DefaultValue(“defaultVal”) datatype varName

Ex:
@GET
@Path("eligibleBooks")
public ProductInfos getEligibleProducts(
 @QueryParam("category") @DefaultValue("JAVA") String category,
 @QueryParam(bookId) String bookId, 
 @QueryParam("bookName") String bookName,
 @QueryParam("accountType") String accountType,
 @QueryParam("countryCode") @DefaultValue("US") String countryCode) {
    
 //TODO method body
}

Target URL: /eligibleBooks?category=JAVA&bookId=1234&bookName=abcd123&accountType=technology&countryCode=IN