SyntaxHighlighter

Showing posts with label Spring Web MVC. Show all posts
Showing posts with label Spring Web MVC. Show all posts

Tuesday, April 23, 2013

Spring Web MVC and Spring Integration - Types of Applications

Spring MVC and Spring Integration - Types of Applications


here's a quick bit of theory regarding types of applications in regards to Spring Integration and Spring Web MVC.

so, Spring Integration can do a lot of things and has HTTP endpoints which, would appear to be the same sort of thing that Spring Web MVC does, but in XML.  well, not quite.  there's kind of two directions involved in these frameworks;

Spring MVC is HTTP 1st, Service 2nd
Spring Integration is Service 1st (accessed via messages) and HTTP 2nd (along with JMS, XMPP, FTP, TCP/IP, etc.)

if you're building an application that is a service first, and it's access 2nd.  (for example, a record retrieval service or a lookup service), i would go Spring Integration to expose the service via messages.  then, as protocols were required (JMS, HTTP, etc.) you can add endpoints.

if you're building something that is primarily to be served as a website (HTTP), though Spring Integration can do this (it's underlying objects are Spring WebMVC ones), i would go in favor of the Spring WebMVC pattern if only for the wealth of documents and support.

though the Enterprise Integration Pattern has been around a while (10 years October 2013) - it appears to have been only viewed as a backend solution.

Spring Integration is damn useful, but in some cases, a bit of overkill

Wednesday, April 17, 2013

Spring WebMVC - returning XML instead of JSON using XStream

Spring WebMVC - returning XML instead of JSON using XStream

here's a little set of code i put together in response to a stackoverflow question (http://stackoverflow.com/questions/16060973/configuring-spring-mvc-rest-to-return-only-xml/160621420)

here's the entity that i'm going to expose

package de.incompleteco.spring.domain;

import java.io.Serializable;

public class SimpleEntity implements Serializable {

 private Long id;
 
 private String stuff;
 
 public SimpleEntity() {
  this.id = System.currentTimeMillis();
 }

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public String getStuff() {
  return stuff;
 }

 public void setStuff(String stuff) {
  this.stuff = stuff;
 }
 
 
 
}


here's the very simple controller

package de.incompleteco.spring.web.controller;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import de.incompleteco.spring.domain.SimpleEntity;

@Controller
@RequestMapping("/simpleEntity")
public class SimpleRestController {

 
 @RequestMapping(method=RequestMethod.GET,produces=MediaType.APPLICATION_XML_VALUE)
 public @ResponseBody SimpleEntity get() {
  return new SimpleEntity();
 }
 
}



here's the xml way of wiring it up to use XStream as the XML Streaming engine


 
  
   
    
    
    
     
      #{T(org.springframework.http.MediaType).APPLICATION_XML_VALUE}
     
    
   
  
 
 
 

 





here's the @Configuration way to do the same

package de.incompleteco.spring.web;

import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.oxm.xstream.XStreamMarshaller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
@ComponentScan("de.incompleteco.spring.web")
public class SimpleConfiguration extends WebMvcConfigurerAdapter {
 
 private XStreamMarshaller marshaller;
 
 @Override
 public void configureMessageConverters(List> converters) {
  converters.add(getHttpMessageConverter());
  super.configureMessageConverters(converters);
  
 }

 public HttpMessageConverter getHttpMessageConverter() {
  MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter();
  converter.setMarshaller(marshaller());
  converter.setUnmarshaller(marshaller());
  return converter;
 }

 @Bean
 public AbstractMarshaller marshaller() {
  if (marshaller == null) {
   return new XStreamMarshaller();
  } else {
   return marshaller;
  }
 }
 
}



and here's the tests for the code.
package de.incompleteco.spring.web.controller;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({"classpath:/META-INF/spring/servlet-context.xml"})
public class SimpleRestControllerTest {

 @Resource
 private WebApplicationContext context;
 
 @Test
 public void testGet() throws Exception {
  MockMvc mvc = webAppContextSetup(context).build();
  //test
  MvcResult result = mvc.perform(get("/simpleEntity").contentType(MediaType.TEXT_HTML)).andExpect(status().isOk()).andReturn();
  //now show the context
  System.out.println(result.getResponse().getContentAsString());
 }

}



and
package de.incompleteco.spring.web.controller;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.web.context.WebApplicationContext;

import de.incompleteco.spring.web.SimpleConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes=SimpleConfiguration.class)
public class ConfigSimpleRestControllerTest {

 @Resource
 private WebApplicationContext context;
 
 @Test
 public void testGet() throws Exception {
  MockMvc mvc = webAppContextSetup(context).build();
  //test
  MvcResult result = mvc.perform(get("/simpleEntity").contentType(MediaType.TEXT_HTML)).andExpect(status().isOk()).andReturn();
  //now show the context
  System.out.println(result.getResponse().getContentAsString());
 }

}


one thing to note: you'll need to comment out/keep the @Configuration separate from the XML - the XML scans and hits the @Configuration annotation and tries to an appcontext inside and appcontext (and dies)

and here's the pom too...

  4.0.0
  de.incompleteco.spring.webmvc
  spring-webmvc-rest-xml
  0.0.1-SNAPSHOT
  war
  spring-webmvc-rest-xml
  
   
     
       org.apache.maven.plugins
       maven-compiler-plugin
       
         1.7
         1.7
       
     
      
    
  
   
    org.springframework
    spring-webmvc
    3.2.1.RELEASE
   
   
    org.springframework
    spring-test
    3.2.1.RELEASE
    test
   
   
    junit
    junit
    4.10
    test
   
   
    javax.servlet
    javax.servlet-api
    3.0.1
    provided
   
   
    org.springframework
    spring-web
    3.2.1.RELEASE
   
   
    log4j
    log4j
    1.2.17
    test
   
   
    org.springframework
    spring-oxm
    3.2.1.RELEASE
   
   
    com.thoughtworks.xstream
    xstream
    1.4.4
   
  

Monday, January 7, 2013

WebApplicationInitializer and WebSphere 8

WebApplicationInitializer and WebSphere 8

so, it would appear that WebSphere 8 supports Servlet 3.0 in it's web.xml-less form, but... it doesn't want to play nice with Spring's WebApplicationInitializer.

when using the new AbstractDispatcherServletInitializer (an abstract of WebApplicationInitializer) it doesn't get triggered and start-up.

bit of nuisance that, but lets see if i can fix it...

Sunday, January 6, 2013

Spring WebMVC 3.2 and Validation

Spring WebMVC 3.2 and Validation

Spring 3.2 WebMVC has a neat new feature regarding validation and error handling.  Let's say we have the following use case;
- objects are POSTed as JSON
- objects are @Valid on arrival
- any validation errors are returned as parsed JSON responses inside the body of the reply so that the client can process

so, first we have our normal request processor

package de.incompleteco.spring.web.controller;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import de.incompleteco.spring.web.domain.SimpleEntity;

@Controller
public class ValidatorController {

 @RequestMapping(value="/simpleEntity",method=RequestMethod.POST)
 public SimpleEntity process(@Valid SimpleEntity simpleEntity) throws Exception {
  System.out.println("got it here");
  simpleEntity.setProcessed("true");
  return simpleEntity;
 }
 
}

and here's the entity

package de.incompleteco.spring.web.domain;

import java.io.Serializable;

import javax.validation.constraints.NotNull;

public class SimpleEntity implements Serializable {

 private static final long serialVersionUID = 1L;

 @NotNull
 private Long id;
 
 private String processed;

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public String getProcessed() {
  return processed;
 }

 public void setProcessed(String processed) {
  this.processed = processed;
 }
 
 
 
}

so if we pass it in without the id set, we'll get a BindingException.

with Spring 3.2 WebMVC, here's how we can catch all the BindingExceptions across the application and return them.  we want to return a 400 status code and the ObjectErrors in the body of the response.

package de.incompleteco.spring.web.controller;

import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import de.incompleteco.spring.web.domain.ErrorEntity;

@ControllerAdvice
public class ValidatorAdvice {

 @ExceptionHandler(BindException.class)
 public @ResponseBody ErrorEntity handleException(BindException exception,HttpServletResponse response) {
  ErrorEntity entity = new ErrorEntity();
  entity.setErrors(exception.getBindingResult().getAllErrors());
  //set the response status
  response.setStatus(HttpStatus.BAD_REQUEST.value());
  //return
  return entity;
  
 }
 
}


and here's our "payload" entity

package de.incompleteco.spring.web.domain;

import java.io.Serializable;
import java.util.List;

import org.springframework.validation.ObjectError;

public class ErrorEntity implements Serializable {

 private List< ObjectError > errors;

 public List< ObjectError > getErrors() {
  return errors;
 }

 public void setErrors(List< ObjectError > errors) {
  this.errors = errors;
 }
 
}


what our result will be is the ErrorEntity processed via Jackson (JSON) and the status code set to 400.

by the way, our Spring configuration is this;




 
 
 



don't ya love 3.2!

Thursday, December 20, 2012

Maven and Servlet 3.0 - no web.xml

Maven and Servlet 3.0 - no web.xml

something i keep forgetting is how to set maven pom to ignore when it doesn't have a web.xml... so here 'tis

Sunday, September 23, 2012

Spring @Valid and JSON

Spring @Valid and JSON


a neat feature of Spring 3.1 is the ability to set @ExceptionHandler for types thrown by controller methods.  in a JSON scenario, we may wish to format the error back to the client and the @ExceptionHandler allows us to do exactly that.

here's how to do it;

let's create the entities, including an error encapsulating entity





now create an abstract error controller (for reuse design)



now let's use that in a controller



and, of course, the wiring





Friday, September 21, 2012

WebSphere Gotcha - Streaming in WAS 8

WebSphere Gotcha - Streaming in WAS 8

here's a little gotcha in WebSphere 8; if you're using Spring MVC and you decide to serve non-jsp content from behind the WEB-INF directory (e.g. a javascript file), the ViewResolver must return it as a jsp page, otherwise WAS will block it.

In tomcat or other servlet container it will work, but in WebSphere, I can't get it to.

My workaround

create a controller that will stream it back in the HttpServletResponse object

Friday, July 27, 2012

Spring Web MVC and ErrorHandler

Spring Web MVC and ErrorHandler

i think i'm a bit thick but one of the things that kept screwing up my use of an overriding ExceptionHandler in Spring Web MVC was where i was setting it.  don't set it with your mvc application context but set it with the ContextLoaderListener one, this way it's loaded before the DispatcherServlet and can be used, otherwise it loads the default.

simple tip, but one that had me stumped... not that i should be surprised