diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
index 86912f52888..8a3dc70120c 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
@@ -16,40 +16,56 @@
package org.springframework.web.servlet.config;
+import org.w3c.dom.Element;
+
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
+import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
+import org.springframework.http.converter.ByteArrayHttpMessageConverter;
+import org.springframework.http.converter.FormHttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
+import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
+import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
-import org.w3c.dom.Element;
/**
- * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses the {@code annotation-driven} element to configure
- * a Spring MVC web application.
- *
- * Responsible for:
+ * {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring MVC web
+ * application.
+ *
+ *
Responsible for:
*
- * - Registering a DefaultAnnotationHandlerMapping bean for mapping HTTP Servlet Requests to @Controller methods using @RequestMapping annotations.
+ *
- Registering a DefaultAnnotationHandlerMapping bean for mapping HTTP Servlet Requests to @Controller methods
+ * using @RequestMapping annotations.
*
- Registering a AnnotationMethodHandlerAdapter bean for invoking annotated @Controller methods.
- * Will configure the HandlerAdapter's
webBindingInitializer property for centrally configuring @Controller DataBinder instances:
+ * Will configure the HandlerAdapter's webBindingInitializer property for centrally configuring
+ * {@code @Controller} {@code DataBinder} instances:
*
- * - Configures the conversionService if specified, otherwise defaults to a fresh {@link ConversionService} instance created by the default {@link FormattingConversionServiceFactoryBean}.
- *
- Configures the validator if specified, otherwise defaults to a fresh {@link Validator} instance created by the default {@link LocalValidatorFactoryBean} if the JSR-303 API is present in the classpath.
+ *
- Configures the conversionService if specified, otherwise defaults to a fresh {@link ConversionService} instance
+ * created by the default {@link FormattingConversionServiceFactoryBean}.
+ *
- Configures the validator if specified, otherwise defaults to a fresh {@link Validator} instance created by the
+ * default {@link LocalValidatorFactoryBean} if the JSR-303 API is present on the classpath.
+ *
- Configures standard {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters},
+ * including the {@link Jaxb2RootElementHttpMessageConverter} if JAXB2 is present on the classpath, and
+ * the {@link MappingJacksonHttpMessageConverter} if Jackson is present on the classpath.
*
*
*
* @author Keith Donald
* @author Juergen Hoeller
+ * @author Arjen Poutsma
* @since 3.0
*/
public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@@ -57,6 +73,14 @@ public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParse
private static final boolean jsr303Present = ClassUtils.isPresent(
"javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
+ private static final boolean jaxb2Present =
+ ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
+
+ private static final boolean jacksonPresent =
+ ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) &&
+ ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
+
+
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
@@ -74,6 +98,7 @@ public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParse
RootBeanDefinition annAdapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
annAdapterDef.setSource(source);
annAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
+ annAdapterDef.getPropertyValues().add("messageConverters", getMessageConverters(source));
String adapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
@@ -113,4 +138,20 @@ public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParse
}
}
+ private ManagedList getMessageConverters(Object source) {
+ ManagedList messageConverters = new ManagedList();
+ messageConverters.setSource(source);
+ messageConverters.add(new RootBeanDefinition(ByteArrayHttpMessageConverter.class));
+ messageConverters.add(new RootBeanDefinition(StringHttpMessageConverter.class));
+ messageConverters.add(new RootBeanDefinition(FormHttpMessageConverter.class));
+ messageConverters.add(new RootBeanDefinition(SourceHttpMessageConverter.class));
+ if (jaxb2Present) {
+ messageConverters.add(new RootBeanDefinition(Jaxb2RootElementHttpMessageConverter.class));
+ }
+ if (jacksonPresent) {
+ messageConverters.add(new RootBeanDefinition(MappingJacksonHttpMessageConverter.class));
+ }
+ return messageConverters;
+ }
+
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
index e7ba282e2a5..6f33665f96e 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
@@ -319,6 +319,14 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
this.customModelAndViewResolvers = customModelAndViewResolvers;
}
+ /**
+ * Returns the message body converters to use. These converters are used to convert from and to HTTP requests and
+ * responses.
+ */
+ public HttpMessageConverter>[] getMessageConverters() {
+ return messageConverters;
+ }
+
/**
* Set the message body converters to use. These converters are used to convert from and to HTTP requests and
* responses.
@@ -605,7 +613,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
private ServletHandlerMethodInvoker(HandlerMethodResolver resolver) {
super(resolver, webBindingInitializer, sessionAttributeStore, parameterNameDiscoverer,
- customArgumentResolvers, messageConverters);
+ customArgumentResolvers, getMessageConverters());
}
@Override
@@ -792,8 +800,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
HttpOutputMessage outputMessage = new ServletServerHttpResponse(webRequest.getResponse());
Class> returnValueType = returnValue.getClass();
List allSupportedMediaTypes = new ArrayList();
- if (messageConverters != null) {
- for (HttpMessageConverter messageConverter : messageConverters) {
+ if (getMessageConverters() != null) {
+ for (HttpMessageConverter messageConverter : getMessageConverters()) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
for (MediaType acceptedMediaType : acceptedMediaTypes) {
if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
index b9f8eeea1d1..459f066cf5a 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
@@ -16,20 +16,15 @@
package org.springframework.web.servlet.config;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
import java.util.Date;
import java.util.Locale;
-
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
+import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
+
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.convert.ConversionFailedException;
@@ -38,6 +33,13 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
+import org.springframework.http.converter.ByteArrayHttpMessageConverter;
+import org.springframework.http.converter.FormHttpMessageConverter;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
+import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
+import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
@@ -61,35 +63,47 @@ import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
/**
* @author Keith Donald
+ * @author Arjen Poutsma
*/
public class MvcNamespaceTests {
- private GenericWebApplicationContext container;
+ private GenericWebApplicationContext appContext;
@Before
public void setUp() {
- container = new GenericWebApplicationContext();
- container.setServletContext(new MockServletContext());
+ appContext = new GenericWebApplicationContext();
+ appContext.setServletContext(new MockServletContext());
LocaleContextHolder.setLocale(Locale.US);
}
@Test
public void testDefaultConfig() throws Exception {
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container);
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config.xml", getClass()));
- assertEquals(4, container.getBeanDefinitionCount());
- container.refresh();
+ assertEquals(4, appContext.getBeanDefinitionCount());
+ appContext.refresh();
- DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class);
+ DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
assertNotNull(mapping);
assertEquals(0, mapping.getOrder());
- AnnotationMethodHandlerAdapter adapter = container.getBean(AnnotationMethodHandlerAdapter.class);
+ AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
assertNotNull(adapter);
- assertNotNull(container.getBean(FormattingConversionServiceFactoryBean.class));
- assertNotNull(container.getBean(ConversionService.class));
- assertNotNull(container.getBean(LocalValidatorFactoryBean.class));
- assertNotNull(container.getBean(Validator.class));
+
+ HttpMessageConverter[] messageConverters = adapter.getMessageConverters();
+ assertNotNull(messageConverters);
+ assertEquals(6, messageConverters.length);
+ assertTrue(ByteArrayHttpMessageConverter.class.equals(messageConverters[0].getClass()));
+ assertTrue(StringHttpMessageConverter.class.equals(messageConverters[1].getClass()));
+ assertTrue(FormHttpMessageConverter.class.equals(messageConverters[2].getClass()));
+ assertTrue(SourceHttpMessageConverter.class.equals(messageConverters[3].getClass()));
+ assertTrue(Jaxb2RootElementHttpMessageConverter.class.equals(messageConverters[4].getClass()));
+ assertTrue(MappingJacksonHttpMessageConverter.class.equals(messageConverters[5].getClass()));
+
+ assertNotNull(appContext.getBean(FormattingConversionServiceFactoryBean.class));
+ assertNotNull(appContext.getBean(ConversionService.class));
+ assertNotNull(appContext.getBean(LocalValidatorFactoryBean.class));
+ assertNotNull(appContext.getBean(Validator.class));
TestController handler = new TestController();
@@ -103,12 +117,12 @@ public class MvcNamespaceTests {
@Test(expected=ConversionFailedException.class)
public void testCustomConversionService() throws Exception {
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container);
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-custom-conversion-service.xml", getClass()));
- assertEquals(4, container.getBeanDefinitionCount());
- container.refresh();
+ assertEquals(4, appContext.getBeanDefinitionCount());
+ appContext.refresh();
- AnnotationMethodHandlerAdapter adapter = container.getBean(AnnotationMethodHandlerAdapter.class);
+ AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
assertNotNull(adapter);
TestController handler = new TestController();
@@ -122,12 +136,12 @@ public class MvcNamespaceTests {
@Test
public void testCustomValidator() throws Exception {
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container);
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-custom-validator.xml", getClass()));
- assertEquals(4, container.getBeanDefinitionCount());
- container.refresh();
+ assertEquals(4, appContext.getBeanDefinitionCount());
+ appContext.refresh();
- AnnotationMethodHandlerAdapter adapter = container.getBean(AnnotationMethodHandlerAdapter.class);
+ AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
assertNotNull(adapter);
TestController handler = new TestController();
@@ -138,18 +152,18 @@ public class MvcNamespaceTests {
MockHttpServletResponse response = new MockHttpServletResponse();
adapter.handle(request, response, handler);
- assertTrue(container.getBean(TestValidator.class).validatorInvoked);
+ assertTrue(appContext.getBean(TestValidator.class).validatorInvoked);
assertFalse(handler.recordedValidationError);
}
@Test
public void testInterceptors() throws Exception {
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container);
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-interceptors.xml", getClass()));
- assertEquals(7, container.getBeanDefinitionCount());
- container.refresh();
+ assertEquals(7, appContext.getBeanDefinitionCount());
+ appContext.refresh();
- DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class);
+ DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
assertNotNull(mapping);
mapping.setDefaultHandler(new TestController());
@@ -177,12 +191,12 @@ public class MvcNamespaceTests {
@Test
public void testBeanDecoration() throws Exception {
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container);
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-bean-decoration.xml", getClass()));
- assertEquals(6, container.getBeanDefinitionCount());
- container.refresh();
+ assertEquals(6, appContext.getBeanDefinitionCount());
+ appContext.refresh();
- DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class);
+ DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
assertNotNull(mapping);
mapping.setDefaultHandler(new TestController());
@@ -199,12 +213,12 @@ public class MvcNamespaceTests {
@Test
public void testViewControllers() throws Exception {
- XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container);
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-view-controllers.xml", getClass()));
- assertEquals(8, container.getBeanDefinitionCount());
- container.refresh();
+ assertEquals(8, appContext.getBeanDefinitionCount());
+ appContext.refresh();
- DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class);
+ DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
assertNotNull(mapping);
mapping.setDefaultHandler(new TestController());
@@ -214,10 +228,10 @@ public class MvcNamespaceTests {
assertEquals(3, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor);
- SimpleUrlHandlerMapping mapping2 = container.getBean(SimpleUrlHandlerMapping.class);
+ SimpleUrlHandlerMapping mapping2 = appContext.getBean(SimpleUrlHandlerMapping.class);
assertNotNull(mapping2);
- SimpleControllerHandlerAdapter adapter = container.getBean(SimpleControllerHandlerAdapter.class);
+ SimpleControllerHandlerAdapter adapter = appContext.getBean(SimpleControllerHandlerAdapter.class);
assertNotNull(adapter);
request.setRequestURI("/foo");