Saturday, February 26, 2011

Spring 3: REST Web Service Provider and Client Tutorial (Part 1)

In this tutorial we'll create a RESTful web service based on Spring 3. We'll be developing a REST provider using URI templates that returns XML and JSON representations of our data. We'll also add basic support for retrieving images and html pages. We'll test our provider via RESTClient to verify the service's availability. In part 2, we'll add an actual client based on RestTemplate and Spring MVC that will access our service.

What is REST?
Representational State Transfer (REST) is a style of software architecture for distributed hypermedia systems such as the World Wide Web. The term Representational State Transfer was introduced and defined in 2000 by Roy Fielding in his doctoral dissertation.

Source: http://en.wikipedia.org/wiki/Representational_State_Transfer

The Representational State Transfer (REST) style is an abstraction of the architectural elements within a distributed hypermedia system. REST ignores the details of component implementation and protocol syntax in order to focus on the roles of components, the constraints upon their interaction with other components, and their interpretation of significant data elements. It encompasses the fundamental constraints upon components, connectors, and data that define the basis of the Web architecture, and thus the essence of its behavior as a network-based application.

Source: Architectural Styles and the Design of Network-based Software Architectures, a dissertation of Roy Thomas Fielding,

REST vs SOAP
Unlike SOAP-based web services, there is no "official" standard for RESTful web services. This is because REST is an architecture, unlike SOAP, which is a protocol. Even though REST is not a standard, a RESTful implementation such as the Web can use standards like HTTP, URL, XML, PNG, etc.

Source: http://en.wikipedia.org/wiki/Representational_State_Transfer

What is REST in Spring 3?
For a great introduction, please see the following links:
- REST in Spring 3: @MVC
- REST in Spring 3: RestTemplate

The Provider

Our application is a simple CRUD system for managing a list of persons. We'll start our project with the provider service which produces XML and JSON representations of our data.

The Domain Layer

We'll be declaring two domain objects: Person and PersonList

Person.java
package org.krams.tutorial.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="person")
public class Person {

 private Long id;
 private String firstName;
 private String lastName;
 private Double money;
 
 public Long getId() {
  return id;
 }
 public void setId(Long id) {
  this.id = id;
 }
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public Double getMoney() {
  return money;
 }
 public void setMoney(Double money) {
  this.money = money;
 }
}
Person is a simple POJO consisting of three properties. Notice we've annotated the class name with @XmlRootElement(name="person"). Its purpose is to help JAXB (the one responsible for marshalling/unmarshalling to XML) determine the root of our POJO.

PersonList.java
package org.krams.tutorial.domain;

import java.util.List;

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

@XmlRootElement(name="persons")
public class PersonList {

 @XmlElement(required = true)
 public List<person> data;

 @XmlElement(required = false)
 public List<person> getData() {
  return data;
 }

 public void setData(List<person> data) {
  this.data = data;
 }
}
PersonList is another simple POJO. It's purpose is to wrap a list of Person objects.

Ideally we should be able to return a List instead of a PersonList. However, JAXB has difficulties processing java.util.List. A simple Google search verifies this unwanted behavior, for example, http://stackoverflow.com/questions/298733/java-util-list-is-an-interface-and-jaxb-cant-handle-interfaces

To resolve this issue with JAXB, we wrap our List with another object. To learn more about JAXB please visit the following link: http://download.oracle.com/javaee/5/tutorial/doc/bnazf.html

The Controller Layer

The controller layer is the most important section of the provider service because here's where we define the RESTful services available to our clients.

ProviderController.java
package org.krams.tutorial.controller;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.imageio.ImageIO;
import org.apache.log4j.Logger;
import org.krams.tutorial.domain.Person;
import org.krams.tutorial.domain.PersonList;
import org.krams.tutorial.service.PersonService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;

/**
 * REST service provider
 * 
 * Only GET and POST will return values
 * PUT and DELETE will not.
 */
@Controller
@RequestMapping("/provider")
public class RestProviderController {

 protected static Logger logger = Logger.getLogger("controller");
 
 @Resource(name="personService")
 private PersonService personService;
 
 @RequestMapping(value = "/person/{id}", 
        method = RequestMethod.GET,
        headers="Accept=image/jpeg, image/jpg, image/png, image/gif")
 public @ResponseBody byte[] getPhoto(@PathVariable("id") Long id) {
  
  // Call service here
  try {
   // Retrieve image from the classpath
   InputStream is = this.getClass().getResourceAsStream("/bella.jpg"); 
   
   // Prepare buffered image
   BufferedImage img = ImageIO.read(is);
   
   // Create a byte array output stream
   ByteArrayOutputStream bao = new ByteArrayOutputStream();
   
   // Write to output stream
   ImageIO.write(img, "jpg", bao);
   
   logger.debug("Retrieving photo as byte array image");
   return bao.toByteArray();
   
  } catch (IOException e) {
   logger.error(e);
   throw new RuntimeException(e);
  }
 }
    
    @RequestMapping(value = "/person/{id}", 
        method = RequestMethod.GET, 
        headers="Accept=application/html, application/xhtml+xml")
 public String getPersonHTML(@PathVariable("id") Long id, Model model) {
     logger.debug("Provider has received request to get person with id: " + id);
  
  // Call service to here
  model.addAttribute("person",personService.get(id));
  
  return "getpage";
 }
    
 @RequestMapping(value = "/persons", 
        method = RequestMethod.GET, 
        headers="Accept=application/xml, application/json")
 public @ResponseBody PersonList getPerson() {
  logger.debug("Provider has received request to get all persons");
  
  // Call service here
  PersonList result = new PersonList();
  result.setData(personService.getAll());
  
  return result;
 }
 
    @RequestMapping(value = "/person/{id}", 
           method = RequestMethod.GET, 
           headers="Accept=application/xml, application/json")
 public @ResponseBody Person getPerson(@PathVariable("id") Long id) {
     logger.debug("Provider has received request to get person with id: " + id);
     
     // Call service here
  return personService.get(id);
    }
    
    @RequestMapping(value = "/person", 
           method = RequestMethod.POST, 
           headers="Accept=application/xml, application/json")
 public @ResponseBody Person addPerson(@RequestBody Person person) {
     logger.debug("Provider has received request to add new person");
     
     // Call service to here
     return personService.add(person);
    }
    
    
    @RequestMapping(value = "/person/{id}", 
           method = RequestMethod.PUT, 
           headers="Accept=application/xml, application/json")
 public @ResponseBody String updatePerson(@RequestBody Person person) {
     logger.debug("Provider has received request to edit person with id: " + id);
     
     // Call service here
     person.setId(id);
     return personService.edit(person).toString();
    }
    
    
    @RequestMapping(value = "/person/{id}", 
           method = RequestMethod.DELETE,
           headers="Accept=application/xml, application/json")
 public @ResponseBody String deleteEmployee(@PathVariable("id") Long id) {
     logger.debug("Provider has received request to delete person with id: " + id);
 
     // Call service here
     return personService.delete(id).toString();
    }
}

The URI Templates
Our controller has seven methods available. The first four are GET methods while the last three are POST, PUT, and DELETE methods.

The four GET methods correspond to the following:

1. Retrieving a single image based on a specific id
URL: http://localhost:8080/spring-rest-provider/krams/person/{id} 
Method: GET
Accept Header: image/jpeg, image/jpg, image/png, image/gif

2. Retrieving an HTML page based on a specific id
URL: http://localhost:8080/spring-rest-provider/krams/person/{id}
Method: GET
Accept Header: application/html, application/xhtml+xml

3. Retrieving an XML or JSON containing a list of persons
URL: http://localhost:8080/spring-rest-provider/krams/person
Method: GET
Accept Header: application/xml, application/json

4. Retrieving an XML or JSON containing a single person
URL: http://localhost:8080/spring-rest-provider/krams/person/{id}
Method: GET
Accept Header: application/xml, application/json

The last three methods correspond to the remaining CRUD services:

5. Adding a new person via XML and JSON
URL: http://localhost:8080/spring-rest-provider/krams/person
Method: POST
Accept Header: application/xml, application/json

6. Editing an existing person via XML and JSON
URL: http://localhost:8080/spring-rest-provider/krams/person/{id}
Method: PUT
Accept Header: application/xml, application/json

7. Deleting an existing person via its id
URL: http://localhost:8080/spring-rest-provider/krams/person/{id}
Method: DELETE
Accept Header: application/xml, application/json

HTTP Methods
Notice for most of the methods, we're just reusing the same URL http://localhost:8080/spring-rest-provider/krams/person and the only part that differs are the suffix {id} and the HTTP methods:

Method Purpose
GET Retrieves a representation of the requested resource
POST Creates a new representation of the requested resource
PUT Updates an existing representation of the requested resource
DELETE Deletes an existing representation of the requested resource

The Service Layer

The service layer is the one that does the actual processing of data. Here we're just managing an in-memory list to make the tutorial simpler to understand. Translating this to a real database isn't really that difficult

PersonService.java
package org.krams.tutorial.service;

import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.krams.tutorial.domain.Person;
import org.springframework.stereotype.Service;

@Service("personService")
public class PersonService {

 protected static Logger logger = Logger.getLogger("service");
 
 // In-memory list
 private List<Person> persons = new ArrayList<Person>();
 
 public PersonService() {
  logger.debug("Init database");
  
  // Create in-memory list
  Person person1 = new Person();
  person1.setId(0L);
  person1.setFirstName("John");
  person1.setLastName("Smith");
  person1.setMoney(1000.0);
  
  Person person2 = new Person();
  person2.setId(1L);
  person2.setFirstName("Jane");
  person2.setLastName("Adams");
  person2.setMoney(2000.0);
  
  Person person3 = new Person();
  person3.setId(2L);
  person3.setFirstName("Jeff");
  person3.setLastName("Mayer");
  person3.setMoney(3000.0);
  
  persons.add(person1);
  persons.add(person2);
  persons.add(person3);
 }
 
 /**
  * Retrieves all persons
  */
 public List<Person> getAll() {
  logger.debug("Retrieving all persons");
  
  return persons;
 }
 
 /**
  * Retrieves a single person
  */
 public Person get( Long id ) {
  logger.debug("Retrieving person with id: " + id);
  
  for (Person person:persons) {
   if (person.getId().longValue() == id.longValue()) {
    logger.debug("Found record");
    return person;
   }
  }
  
  logger.debug("No records found");
  return null;
 }
 
 /**
  * Adds a new person
  */
 public Person add(Person person) {
  logger.debug("Adding new person");
  
  try {
   // Find suitable id
   Long newId = 0L;
   Boolean hasFoundSuitableId = false;
   while(hasFoundSuitableId == false) {
    for (int i=0; i <persons.size(); i++) {
     if (persons.get(i).getId().longValue() == newId.longValue()) {
      newId++;
      break;
     }
     
     // Exit while loop
     if(i==persons.size()-1) {
      logger.debug("Assigning id: " + newId);
      hasFoundSuitableId = true;
     }
    }
   }
   
   // Assign new id
   person.setId(newId);
   // Add to list
   persons.add(person);
   
   logger.debug("Added new person");
   return person;
  } catch (Exception e) {
   logger.error(e);
   return null;
  }
 }
 
 /**
  * Deletes an existing person
  */
 public Boolean delete(Long id) {
  logger.debug("Deleting person with id: " + id);
  
  try {
   for (Person person:persons) {
    if (person.getId().longValue() == id.longValue()) {
     logger.debug("Found record");
     persons.remove(person);
     return true;
    }
   }
   
   logger.debug("No records found");
   return false;
   
  } catch (Exception e) {
   logger.error(e);
   return false;
  }
 }
 
 /**
  * Edits an existing person
  */
 public Boolean edit(Person person) {
  logger.debug("Editing person with id: " + person.getId());
  
  try {
   for (Person p:persons) {
    if (p.getId().longValue() == person.getId().longValue()) {
     logger.debug("Found record");
     persons.remove(p);
     persons.add(person);
     return true;
    }
   }
   
   logger.debug("No records found");
   return false;
   
  } catch (Exception e) {
   logger.error(e);
   return false;
  }
 }
}

Configuration

Configuring REST support in Spring isn't really different from configuring your usual Spring MVC. That's because REST in Spring are additional "features to Spring MVC itself" (See Rest in Spring 3: @MVC blog).

Here are all the XML configurations we're using for this project.

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 
 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>/krams/*</url-pattern>
 </servlet-mapping>

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 
</web-app>

spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p" 
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <!-- Declare a view resolver -->
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
      p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

</beans>

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/mvc 
   http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
 <!-- Activates various annotations to be detected in bean classes -->
 <context:annotation-config />
 
 <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
  For example @Controller and @Service. Make sure to set the correct base-package-->
 <context:component-scan base-package="org.krams.tutorial" />
 
 <!-- Configures the annotation-driven Spring MVC Controller programming model.
 Note that, with Spring 3.0, this tag works in Servlet MVC only!  -->
 <mvc:annotation-driven />

</beans>

Run the Application

To run the application, you'll need a client application, like a browser. Also you must access directly the URLs to reach a specific action.

Browser Issues

By default, you can only send a GET request in your browser without resorting to special plugins or tools. When you type a URL in the browser's address field, you're actually specifying a GET request. Using a browser we can only retrieve XML and HTML representations of our GET request (again without resorting to special plugins). Try it out and see what your browser will return.

On Chrome, typing the following URL
http://localhost:8080/spring-rest-provider/krams/person/1
yields an XML document:

On Firefox, typing the following URL
http://localhost:8080/spring-rest-provider/krams/person/1
yields an HTML document:

Testing with RESTClient

Using a browser we can only test the GET portion of the REST service. To fully test all methods, either we write a client application or reuse an existing client. Luckily for us there's a great Java client: RESTClient

What is RESTClient?
RESTClient is a Java application to test RESTful webservices. It can be used to test variety of HTTP communications. From version 2.3 Beta 1, it has two executable Jars:

- GUI version (restclient-ui-X.jar download)
- Cli version for batch execution of .rcq files (restclient-cli-X.jar download)

Source: http://code.google.com/p/rest-client/

Let's start by running RESTClient

Retrieve a single record (GET method)

1. To retrieve a record, select the GET method:

2. Click the Headers tab and enter the following information:
Key:  Accept
Value: application/xml or application/json


Make sure to hit the plus button to enter the values:

3. Enter the following URL:
http://localhost:8080/spring-rest-provider/krams/person/1
You should see the following results depending on the Accept header you provided earlier:

XML result

JSON result

Add a new record (POST method)

1. Under the Method tab, select the POST method.

2. Under the Headers tab, enter the following information:
Key:  Accept
Value: application/xml or application/json

3. Under the body tab, enter the following content (depending on the value field in step #2)
XML:
<person>
    <firstName>Roy</firstName>
    <lastName>Jones</lastName>
    <money>5000</money>
</person>
JSON:
{
  "firstName":"Roy"
  "lastName":"Jones"
  "money":5000
}

4. Enter the following URL:
http://localhost:8080/spring-rest-provider/krams/person
You should see the following results depending on the Accept header you provided earlier:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<person>
    <firstName>Roy</firstName>
    <lastName>Jones</lastName> 
    <money>5000.0</money>
</person>
JSON:
{
  "firstName" : "Roy",
  "lastName" : "Jones",
  "money" : 5000.0
}

Update an existing record (PUT method)

1. Under the Method tab, select the PUT method.

2. Under the Headers tab, enter the following information:
Key:  Accept
Value: application/xml or application/json

3. Under the body tab, enter the following content (depending on the value field in step #2)
XML:
<person>
    <firstName>Roy</firstName>
    <lastName>Jones</lastName>
    <money>5000</money>
</person>
JSON:
{
  "firstName":"Roy",
  "lastName":"Jones",
  "money":5000
}

4. Enter the following URL:
http://localhost:8080/spring-rest-provider/krams/person
You should see the following results depending on the Accept header you provided earlier:
XML:
true
JSON:
true
This means we've successfully updated record #1 with the new information we've provided. To verify if the record has been updated, create a GET request with the following URL:
http://localhost:8080/spring-rest-provider/krams/provider/person/1
Notice the number 1 at the end. That's the same number we used in the PUT method. You should see the updated record.

Delete an existing record (DELETE method)

1. Under the Method tab, select the DELETE method.

2. Under the Headers tab, enter the following information:
Key:  Accept
Value: application/xml or application/json

3. Enter the following URL:
http://localhost:8080/spring-rest-provider/krams/person/1
You should see the following results depending on the Accept header you provided earlier:
XML:
true
JSON:
true
This means we've successfully deleted record #1. To verify if the record has been deleted, create a GET request with the following URL:
http://localhost:8080/spring-rest-provider/krams/provider/person/1

Notice the number 1 at the end. That's the same number we used in the DELETE method. You should see an empty result.

Conclusion

That's it. We've managed to create a REST service using Spring 3. We've also shown how we can retrieve different representations of our resource by using a unified URL with varying HTTP methods. We've also tested the application using RESTClient. In Part 2 of the tutorial, we'll explore how to develop a client application using Spring's RestTemplate support.

To see Part 2 of this tutorial, click the following link: Spring 3: REST Web Service Provider and Client Tutorial (Part 2)

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-rest-guide/

You can download the project as a Maven build. Look for the spring-rest-provider.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3: REST Web Service Provider and Client Tutorial (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

53 comments:

  1. Hi Karam,

    please provide RestClient(part 2) application with Json object
    its very urgent for me


    ** Restful webservices with Json ***



    Thanks
    venkat

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. One more question is how to handle One to Many relation ships in JAXB? If I have two JPA entities, with One to Many relation ship how to write JAXB annotaions on these entities?

    ReplyDelete
  4. @Srinivas, I believe you just need to write the @XmlRootElement annotation at the top of the class. @ResponseBody will marshall them to their equivalent XML form.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. I haven't seen any of the MessageConverter configured (MappingJacksonHttpMessageConverter,MarshallingHttpMessageConverter), Jaxb2Marshaller.
    Don't we require this configuration?

    ReplyDelete
  7. Hi,

    why i need to declare a viewResolver in spring-servlet.xml if i dont need the .jsp pages but just wanna retrive data as xml ??

    ReplyDelete
  8. @whiteshade, the simple answer is you don't need to if your application doesn't need one.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Excellent tutorial ! Keep up the good work and thank you.

    ReplyDelete
  11. hi can you add src of this project?
    Great totorial...

    ReplyDelete
  12. one stupid question.. I'm using maven and what kind of project i need to create? and with which architype? Thanks....

    ReplyDelete
  13. Great showcase Krams!

    I can get the GET and DELETE to work. But when it comes to PUT and POST I keep getting HTTP Status 415 - The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.

    I guess what it is saying is part of the request was in an unsupported format.

    Does this have something to do with the HTTP request headers when posting. I read somewhere that clients should only send Content-type headers on POST and PUT requests.

    Anyway I'll keep fiddling to see if I can get it to work.

    ReplyDelete
  14. My Bad! I had to add a Request Header Content-Type application/xml. =)

    ReplyDelete
    Replies
    1. Thank you! Had the same problem

      Delete
  15. Thank you for everything!!! Great job!!!

    ReplyDelete
  16. Hi,

    I am getting the following exception with this example. Am I missing any particular JARs or is there any other reason for this error ??
    Please advise.

    The error stack is:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'restProviderController' defined in file [C:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01\installedApps\sapanigr-wxpNode01Cell\PersonDataServiceSpringRestful.ear\TableDataServiceSpringRestful.war\WEB-INF\classes\com\cisco\bic\services\controller\RestProviderController.class]: Post-processing failed of bean type [class com.cisco.bic.services.controller.RestProviderController] failed; nested exception is java.lang.TypeNotPresentException: Type javax.annotation.Resource not present
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:803)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:493)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)

    ReplyDelete
  17. Hi,

    I am getting the JAXB error while stting up the application.

    Please help. The error stack is--

    [12/10/11 14:12:34:366 IST] 00000020 ServletWrappe E SRVE0068E: Uncaught exception thrown in one of the service methods of the servlet: spring. Exception thrown : org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Could not instantiate JAXBContext for class [class com.bic.services.model.CountryList]: 1 counts of IllegalAnnotationExceptions; nested exception is com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
    Class has two properties of the same name "data"
    this problem is related to the following location:
    at public java.util.List com.bic.services.model.CountryList.getData()
    at com.bic.services.model.CountryList
    this problem is related to the following location:
    at public java.util.List com.cisco.bic.services.model.CountryList.data
    at com.cisco.bic.services.model.CountryList

    ReplyDelete
  18. @Saroj, take a carefull look at the exception. It says "Class has two properties of the same name "data"". Make sure to rename one of them.

    ReplyDelete
  19. Great tutorial on both client and provider - simple and works great!!!! Thank you much for this. Saved me a lot of work.

    Ade.

    ReplyDelete
  20. Hi everyone,Thank you very much for this tuto. I want to know how tu use this REST for an android client side.thank you for everything

    ReplyDelete
  21. @xavi, I haven't looked at Android development yet. But you should watch the latest video for Spring Android development which contains samples for accessing services via RestTemplate. See www.springsource.org. Here's the direct link: http://www.springsource.org/node/3505

    ReplyDelete
  22. Very Good!!!
    Thx!!!

    ReplyDelete
  23. This is a fantastic tutorial! All of the books on Spring WS are useless. This tutorial is far better then any book. Excellent work!

    ReplyDelete
  24. Hi krams, very nice tutorial. May I ask if it is possible to get the server's response header in the controller? Can you please provide an example? Kindly please email me at dcrow_14@yahoo.com.ph. Many thanks! :)

    ReplyDelete
  25. Hi karams i like the tutorial ,But is it possible to use a database here
    i need to register the data in database .can you hel me .thanks a lot .

    ReplyDelete
    Replies
    1. sarah, sure you can. You just need to change the PersonService implementation and call your data access layer, i.e DAO or Repository. If you want you can also make your JDBC calls within the PersonService

      Delete
  26. Add a new record (POST method)
    1. Under the Method tab, select the POST method.

    2. Under the Headers tab, enter the following information:

    Key: Accept
    Value: application/json


    3. Under the body tab, enter the following content

    {
    "firstName":"Roy"
    "lastName":"Jones"
    "money":5000
    }


    4. Enter the following URL:

    http://localhost:8080/spring-rest-provider/krams/person

    i get the following output

    {"id":25,"money":null,"lastName":null,"firstName":null}

    please help.. All the values are comng null.

    ReplyDelete
    Replies
    1. But if i submit data with "application/x-www-form-urlencoded" format, it works
      {"id":27,"money":10.0,"lastName":"pat","firstName":"hirale"}

      Delete
    2. Url
      http://localhost:8080/automation_console_version_1/provider/person

      POST

      Content-Type: application/json

      {
      "firstName" : "jATIN",
      "lastName" : "PATEL",
      "money" : 25000.0
      }

      WORKED

      Delete
  27. hi after inserting or updating records how to pass like "isSucess" : true
    in restclent ui can any one give idea

    ReplyDelete
  28. Hi,
    I am new here, tried to follow this nice tutorial, adding an xml user (POST) works, but adding a json user (POST) is not working :

    Add a new record (POST method)
    1. Under the Method tab, select the POST method.

    2. Under the Headers tab, enter the following information:

    Key: Accept
    Value: application/json


    3. Under the body tab, enter the following content

    {
    "firstName":"Roy"
    "lastName":"Jones"
    "money":5000
    }


    4. Enter the following URL:

    http://localhost:8080/spring-rest-provider/krams/person

    Status : HTTP/1.1 400 Bad Request

    ...
    The request sent by the client was syntactically incorrect ().
    ....

    Please your help is appreciated.

    ReplyDelete
    Replies
    1. Hello,

      You're missing the commas in the XML. Try this:

      {
      "firstName":"Roy",
      "lastName":"Jones",
      "money":5000
      }

      Delete
  29. Hi,

    I am getting the JAXB error while stting up the application.

    Please help. The error stack is--

    .springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Could not instantiate JAXBContext for class [class com.sample.provider.PersonList]: 1 counts of IllegalAnnotationExceptions; nested exception is com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
    Class has two properties of the same name "list"
    this problem is related to the following location:
    at public java.util.ArrayList com.sample.provider.PersonList.getList()
    at com.sample.provider.PersonList
    this problem is related to the following location:
    at public java.util.ArrayList com.sample.provider.PersonList.list
    at com.sample.provider.PersonList

    Could you please help on this.which class property I need to change.

    ReplyDelete
  30. please provide a example using hibernate ...need to retrive data from table and also insert data in table using web service in spring...the request data will come as a xml, then this xml data need to insert in db..

    ReplyDelete
  31. Hi

    I am able to compile and deploy this application using maven,but when I enter url http://localhost:8080/spring-rest-provider/krams/person/1 in crome I get 404 error.

    Kindly help me in resolving this issue as I have already spent lot of time on it.

    ReplyDelete
  32. Hi good stuff. But i want to have webservice using Mysql database. What are the changes to do for this example. Its very urgent . Can you please tell me or suggest me a link where i can get info.

    ReplyDelete
  33. Hi karams i like the tutorial ,But i need to register the data in database .can you help me. Please post what are the changes in personservice and controller class. I am using Mysql . Please post.I am very glad if u post.

    ReplyDelete
  34. Hi Karam, Very helpful Tutorial. Also I have implemented ACL in my Java/Spring web application. Now I would like to implement REST with ACL. If user have access READ rights, then user can access GET, if user have access ADD,EDIT then user can access PUT,POST. I dont want to create new ACL database, same database I would like to use in REST web services.

    I would be appreciated if you help me.

    ReplyDelete
  35. Hi! First of all I would like to state the fact that you actually have built a cool resource. And there is also one thing I would like to ask you. Do you have an idea to write in a professional way or owning a blog is just a hobby of yours?

    ReplyDelete
  36. I think most people would do the same when they are headed with the situation.

    ReplyDelete
  37. how can we get the response depending upon our requirement in a browser like json or xml.

    ReplyDelete
  38. This is so good to see that you are in the press. This is so good for your promotion. You want to see more of this in the future. Namitha hot

    ReplyDelete
  39. To those getting this error:
    Class has two properties of the same name "data"

    Just remove the annotation on the class members (instance variables and methods) and you're good to go.

    ReplyDelete
  40. hi.....very nice article.....can you please provide the client code to consume it....it would be very helpful for me....

    ReplyDelete
  41. Thank you very much

    ReplyDelete
  42. I am getting below error

    HTTP Status 405 - Request method 'GET' not supported

    only first method i am able to execute.

    ReplyDelete
  43. I followed all the steps as mentioned above but getting Http status -404 . please help me to solve this problem.

    ReplyDelete
  44. Great work!
    Is there a way to find out the clients url in my service provider?
    Cheers,
    Magnus

    ReplyDelete
  45. Thanks for your great information, the contents are quiet interesting.I will be waiting for your next post. Web development Company in india

    ReplyDelete
  46. Business intelligence analyst
    SQIAR (http://www.sqiar.com/services/bi-strategy/) is a leading Business Intelligence company.Sqiar Provide business intelligence Services Which help the company to present Information in Meaningful form.

    ReplyDelete
  47. Well said, the post is really the freshest on this valuable topic. I fit in with your conclusions and will thirstily look forward to your next updates host a website | hosting

    ReplyDelete