DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How To Validate HTTP Post Request Body - Restful Web Services With Spring Framework | Spring Boot
  • RESTful Web Services With Spring Boot: Reading HTTP POST Request Body
  • Node.js Http Module to Consume Spring RESTful Web Application
  • Build a REST Service That Consumes Any Type of Request Format

Trending

  • DGS GraphQL and Spring Boot
  • Artificial Intelligence, Real Consequences: Balancing Good vs Evil AI [Infographic]
  • Ethical AI in Agile
  • Agentic AI for Automated Application Security and Vulnerability Management
  1. DZone
  2. Coding
  3. Frameworks
  4. Building a RESTful Web Service with Spring 3.1 and Java based Configuration, part 2

Building a RESTful Web Service with Spring 3.1 and Java based Configuration, part 2

By 
Eugen Paraschiv user avatar
Eugen Paraschiv
·
Nov. 02, 11 · Interview
Likes (1)
Comment
Save
Tweet
Share
48.4K Views

Join the DZone community and get the full member experience.

Join For Free

1. Overview

This is the second of a series of posts about setting up a RESTful web service using Spring 3.1 with Java based configuration. The first post of the series focused on bootstrapping the web application; this post will focus on setting up REST in Spring, the Controller and HTTP response codes, configuration of payload marshalling and content negotiation.

2. Understanding REST in Spring

The Spring framework supports 2 ways of creating RESTful services:

  • using MVC with ModelAndView
  • using HTTP message converters

The ModelAndView approach is older and much better documented, but also more verbose and configuration heavy. It tries to shoehorn the REST paradigm into the old model, which is not without problems. The Spring team understood this and provided first-class REST support starting with Spring 3.0.

The new approach, based on HttpMessageConverter and annotations, is much more lightweight and easy to implement. Configuration is minimal and it provides sensible defaults for what you would expect from a RESTful service. It is however newer and a a bit on the light side concerning documentation; what’s more, the Spring reference doesn’t go out of it’s way to make the distinction and the tradeoffs between the two approaches as clear as they should be. Nevertheless, this is the way RESTful services should be build after Spring 3.0.

3. The Java configuration

@Configuration
@EnableWebMvc
public class WebConfig{
   //
}
The new @EnableWebMvc annotation does a number of useful things – specifically, in the case of REST, it detect the existence of Jackson and JAXB 2 on the classpath and automatically creates and registers default JSON and XML converters. The functionality of the annotation is equivalent to the XML version:

<mvc:annotation-driven />

This is a shortcut, and though it may be useful in many situations, it’s not perfect. When more complex configuration is needed, remove the annotation and extend WebMvcConfigurationSupport directly.

4. Testing the Spring context

Starting with Spring 3.1, we get first-class testing support for @Configuration classes:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( classes = { ApplicationConfig.class, PersistenceConfig.class },loader = AnnotationConfigContextLoader.class )
public class SpringTest{
   
   @Test
   public void whenSpringContextIsInstantiated_thenNoExceptions(){
      // When
   }
}

The Java configuration classes are simply specified with the @ContextConfiguration annotation and the new AnnotationConfigContextLoader loads the bean definitions from the @Configuration classes.

Notice that the WebConfig configuration class was not included in the test because it needs to run in a servlet context, which is not provided.

5. The Controller

The @Controller is the central artifact in the entire Web Tier of the RESTful API. For the purpose of this post, the controller is modeling a simple REST resource – Foo:

@Controller
class FooController{
   
   @Autowired
   IFooService service;
   
   @RequestMapping( value = "foo",method = RequestMethod.GET )
   @ResponseBody
   public List< Foo > getAll(){
      return this.service.getAll();
   }
   
   @RequestMapping( value = "foo/{id}",method = RequestMethod.GET )
   @ResponseBody
   public Foo get( @PathVariable( "id" ) Long id ){
      return RestPreconditions.checkNotNull( this.service.getById( id ) );
   }
   
   @RequestMapping( value = "foo",method = RequestMethod.POST )
   @ResponseStatus( HttpStatus.CREATED )
   @ResponseBody
   public Long create( @RequestBody Foo entity ){
      RestPreconditions.checkNotNullFromRequest( entity );
      return this.service.create( entity );
   }
   
   @RequestMapping( value = "foo",method = RequestMethod.PUT )
   @ResponseStatus( HttpStatus.OK )
   public void update( @RequestBody Foo entity ){
      RestPreconditions.checkNotNullFromRequest( entity );
      RestPreconditions.checkNotNull( this.service.getById( entity.getId() ) );
      this.service.update( entity );
   }
   
   @RequestMapping( value = "foo/{id}",method = RequestMethod.DELETE )
   @ResponseStatus( HttpStatus.OK )
   public void delete( @PathVariable( "id" ) Long id ){
      this.service.deleteById( id );
   }
}

The Controller implementation is non-public – this is because there is no need for it to be. Usually the controller is the last in the chain of dependencies – it receives HTTP requests from the Spring front controller (the DispathcerServlet) and simply delegate them forward to a service layer. If there is no use case where the controller has to be injected or manipulated through a direct reference, then I prefer not to declare it as public.

The request mappings are straightforward – as with any Spring controller, the actual value of the mapping as well as the HTTP method are used to determine the target method for the request. @RequestBody will bind the parameters of the method to the body of the HTTP request, whereas @ResponseBody does the same for the response and return type. They also ensure that the resource will be marshalled and unmarshalled using the correct HTTP converter. Content negotiation will take place to choose which one of the active converters will be used, based mostly on the Accept header, although other HTTP headers may be used to determine the representation as well.

6. Mapping the HTTP response codes

The status codes of the HTTP response are one of the most important parts of the REST service, and the subject can quickly become very complex. Getting these right can be what makes or breaks the service.

6.1. Unmapped requests

If Spring MVC receives a request which doesn’t have a mapping, it considers the request not to be allowed and returns a 405 METHOD NOT ALLOWED back to the client. It is also good practice to include the Allow HTTP header when returning a 405 to the client, in order to specify which operations are allowed. This is the standard behavior of Spring MVC and does not require any additional configuration.

6.2. Valid, mapped requests

For any request that does have a mapping, Spring MVC considers the request valid and responds with 200 OK if no other status code is specified otherwise. It is because of this that controller declares different @ResponseStatus for the create, update and delete actions but not for get, which should indeed return the default 200 OK.

6.3. Client error

In case of a client error, custom exceptions are defined and mapped to the appropriate error codes. Simply throwing these exceptions from any of the layers of the web tier will ensure Spring maps the corresponding status code on the HTTP response.

@ResponseStatus( value = HttpStatus.BAD_REQUEST )
public class BadRequestException extends RuntimeException{
   //
}
@ResponseStatus( value = HttpStatus.NOT_FOUND )
public class ResourceNotFoundException extends RuntimeException{
   //
}

These exceptions are part of the REST API and, as such, should only be used in the appropriate layers corresponding to REST; if for instance a DAO/DAL layer exist, it should not use the exceptions directly. Note also that these are not checked exceptions but runtime exceptions – in line with Spring practices and idioms.

6.4. Using @ExceptionHandler

Another option to map custom exceptions on specific status codes is to use the @ExceptionHandler annotation in the controller. The problem with that approach is that the annotation only applies to the controller in which it is defined, not to the entire Spring Container, which means that it needs to be declared in each controller individually. This quickly becomes cumbersome, especially in more complex applications which many controllers. There are a few JIRA issues opened with Spring at this time to handle this and other related limitations: SPR-8124, SPR-7278, SPR-8406.

7. Additional Maven dependencies

In addition to the pom.xml from the first post, two dependencies need to be added:

<dependencies>
   <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>${jackson-mapper-asl.version}</version>
      <scope>runtime</scope>
   </dependency>
   <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>	
      <version>${jaxb-api.version}</version>
      <scope>runtime</scope>
   </dependency>
</dependencies>

<properties>
   <jackson-mapper-asl.version>1.9.12</jackson-mapper-asl.version>
   <jaxb-api.version>2.2.4</jaxb-api.version>
</properties>

These are the libraries used to convert the representation of the REST resource to either JSON or XML.

8. Conclusion

This post covered the configuration and implementation of a RESTful service using Spring 3.1 and Java based configuration, discussing HTTP response codes, basic content negotiation and marshaling. In the next articles of the series I will focus on discoverability of the API, advanced content negotiation and working with additional representations of a resource. In the meantime, check out the github project.

Spring Framework REST Web Protocols Web Service Java (programming language) Requests

Opinions expressed by DZone contributors are their own.

Related

  • How To Validate HTTP Post Request Body - Restful Web Services With Spring Framework | Spring Boot
  • RESTful Web Services With Spring Boot: Reading HTTP POST Request Body
  • Node.js Http Module to Consume Spring RESTful Web Application
  • Build a REST Service That Consumes Any Type of Request Format

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!