Bueno ... era tan difícil de encontrar la respuesta y tuve que seguir para muchas pistas sobre información incompleta que creo que será bueno publicar la respuesta completa aquí. Por lo tanto, será más fácil para el siguiente buscar esto.
primero tenía que poner en práctica el HttpMessageConverter personalizado:
package net.iogui.web.spring.converter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
private Gson gson = new Gson();
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public GsonHttpMessageConverter(){
super(new MediaType("application", "json", DEFAULT_CHARSET));
}
@Override
protected Object readInternal(Class<? extends Object> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
try{
return gson.fromJson(convertStreamToString(inputMessage.getBody()), clazz);
}catch(JsonSyntaxException e){
throw new HttpMessageNotReadableException("Could not read JSON: " + e.getMessage(), e);
}
}
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
@Override
protected void writeInternal(Object t,
HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//TODO: adapt this to be able to receive a list of json objects too
String json = gson.toJson(t);
outputMessage.getBody().write(json.getBytes());
}
//TODO: move this to a more appropriated utils class
public String convertStreamToString(InputStream is) throws IOException {
/*
* To convert the InputStream to String we use the Reader.read(char[]
* buffer) method. We iterate until the Reader return -1 which means
* there's no more data to read. We use the StringWriter class to
* produce the string.
*/
if (is != null) {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
return writer.toString();
} else {
return "";
}
}
}
Luego tuve que quitarse la etiqueta annnotaion impulsada y configurar todo por mis propias manos en el fichero de configuración de primavera-mvc:
<?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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
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">
<!-- Configures the @Controller programming model -->
<!-- To use just with a JSR-303 provider in the classpath
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="net.iogui.web.spring.util.CommonWebBindingInitializer" />
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
<bean class="net.iogui.web.spring.converter.GsonHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" />
<!-- bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /-->
</list>
</property>
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<context:component-scan base-package="net.iogui.teste.web.controller"/>
<!-- Forwards requests to the "/" resource to the "login" view -->
<mvc:view-controller path="/" view-name="home"/>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
Ver que, para hacer el Formater y Validador funcione, tenemos que construir una costumbre webBindingInitializer también:
package net.iogui.web.spring.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;
public class CommonWebBindingInitializer implements WebBindingInitializer {
@Autowired(required=false)
private Validator validator;
@Autowired
private ConversionService conversionService;
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setValidator(validator);
binder.setConversionService(conversionService);
}
}
una cosa interesante que vemos es que el fin de hacer el trabajo de configuración sin la etiqueta de annotaion impulsada , tenemos que configurar manualmente un AnnotationMethodHandlerAdapter y una DefaultAnnotationHandlerMapping.Y con el fin de hacer que el AnnotationMethodHandlerAdapter capaz de manejar el formato y validación, hemos tenido que configurar un validador , un conversionService y construir una costumbre webBindingInitializer.
Espero que todo esto ayude a alguien más aparte de mí.
En mi búsqueda desesperada, this @Bozho publicación fue extremadamente útil. También estoy agradecido a @GaryF por su respuesta que me llevó al @Bozho post. Para ustedes que están tratando de hacer esto en la primavera 3.1, ver la respuesta de @Robby Pond .. Mucho más fácil, ¿no?
Gracias, yo Estoy de acuerdo con Jackson, aunque estaba pensando en cómo haría lo mismo con Gson. Por cierto, podrías haber usado Apache Commons IOUtils para sacar la cadena del InputStream. Normalmente prefiero usar bibliotecas de terceros donde sea posible, ya que no necesito mejorar el código cuando aparece una opción más rápida/mejor, solo cambio la versión en maven :). – Stef
Dado que 'AnnotationMethodHandlerAdapter' ahora está en desuso, ¿funciona esta misma configuración con' RequestMappingHandlerAdapter'? – Stewart