Announcement Announcement Module
No announcement yet.
No XML with JSON/XML xmlfree webmvc jax2 jackson and tiles config with spring 3.2 Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • No XML with JSON/XML xmlfree webmvc jax2 jackson and tiles config with spring 3.2

    Based on the tiles sample project, I want to add RestFUL features, which support JSON and XML either accept-header-based or path-based. Addionally I tried to use a mostly xml-free (java- an annotationbased) approach.

    Everything works as expected but XML -> 406 Error

    This is my controller, which should respond to path based XML and JSON requests

    public class SampleController {
    	SampleService sampleService;
    	@RequestMapping(method = RequestMethod.GET)
    	public List<&gt;> get() {
    		List<Sample> sampleList = sampleService.findAll();
    		return sampleList;
    with a domain object:

    public class Sample implements {
    and some @XmlAttribute 
    My calls to either return XML or JSON looks like this:

    		$("#xmltest").click(function() {
    				url : "services/underlyings.xml",
    				dataType : "xml",
    				accepts :  {xml: 'application/xml'},
    				success : function(retValue) {
    				error: ...
    json is configured with dataType: "json" and accepts : {json: 'application/json'}

    As (every)one can expect, both clicks will result in a "Error Not Acceptable" (Error 406) together with a java error
    Resolving exception from handler [...] org.springframework.web.HttpMediaTypeNotAcceptable Exception: Could not find acceptable representation

    You will find a first solution to solve this problem using the mvc defaults:
    "<mvc:annotation-driven/> configures support for JSON if Jackson is in the classpath, and support for XML if JAXB is present in the classpath"

    In the javabased configuration using the WebMvcConfigAdapter the annotation @EnableWebMvc should be the synonym of <mvc:annotation-driven/>
    So I add to my pom.xml two dependencies

    And voilá, the JSON call works as expected - but the XML request still returns the same 406 error.

    At this point the easiest solution would be to do no additional configuration but make sure, that I choose the "right" dependency for XML-support.
    There are mentioned several issues regarding this theme in spring 3.1 and 3.2 but with no working solution for me.

    After 3 days of crossing the "spring-sea", I haven't found any working sample yet. Either the samples uses
    not the current spring version or the samples have xml configuration and no tiles.

    Before I post my different approches you should be aware of those two config files, which are part of the initial tiles sample project

    @ComponentScan(basePackages = { "",
    		"", "",
    		"" })
    public class WebMvcConfigAdapter extends WebMvcConfigurerAdapter {
    	private static final String MESSAGE_SOURCE = "/WEB-INF/i18n/messages";
    	private static final String TILES = "/WEB-INF/tiles/tiles.xml";
    	private static final String VIEWS = "/WEB-INF/views/**/views.xml";
    	private static final String RESOURCES_LOCATION = "/resources/";
    	private static final String RESOURCES_HANDLER = RESOURCES_LOCATION + "**";
    	@Bean(name = "messageSource")
    	public MessageSource configureMessageSource() {
    		ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    		return messageSource;
    	public TilesViewResolver configureTilesViewResolver() {
    		TilesViewResolver tilesViewResolver = new TilesViewResolver();
    		return tilesViewResolver;
    	public TilesConfigurer configureTilesConfigurer() {
    		TilesConfigurer configurer = new TilesConfigurer();
    		configurer.setDefinitions(new String[] { TILES, VIEWS });
    		return configurer;
    	public Validator getValidator() {
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    	public void configureDefaultServletHandling(
    			DefaultServletHandlerConfigurer configurer) {
    	public void addArgumentResolvers(
    			List<HandlerMethodArgumentResolver> argumentResolvers) {
    	// custom argument resolver inner classes
    and the webapplication initializer

    public class WebAppInitializer implements WebApplicationInitializer {
    	public void onStartup(ServletContext servletContext)
    			throws ServletException {
    		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    		... do some securityfiltering
    		FilterRegistration.Dynamic characterEncodingFilter = servletContext
    						new CharacterEncodingFilter());
    				EnumSet.allOf(DispatcherType.class), true, "/*");
    		characterEncodingFilter.setInitParameter("encoding", "UTF-8");
    		characterEncodingFilter.setInitParameter("forceEncoding", "true");
    		servletContext.addListener(new ContextLoaderListener(context));
    		servletContext.setInitParameter("defaultHtmlEscape", "true");
    		DispatcherServlet servlet = new DispatcherServlet();
    		// no explicit configuration reference here: everything is configured in
    		// the root container for simplicity
    		ServletRegistration.Dynamic appServlet = servletContext.addServlet(
    				"appServlet", servlet);
    		Set<String> mappingConflicts = appServlet.addMapping("/");
    		if (!mappingConflicts.isEmpty()) {
    			throw new IllegalStateException(
    					"'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14");
    I changed code only in the configuration class file of my WebMvcConfigAdapter.
    At this point, I wonder, how jaxb should be aware of my domain classes to convert. On the other hand json can convert java objects
    without a explicit configuration as well, so why should this be necessary for XML ?

    First, I tried several ways to configure (or add) ContentNegotiation:

    This piece of code should replace the default configuration of contentnegotiation that, as described above, should be automatically done
    by spring if the proper libraries are present:

    public void configureContentNegotiation(
    		ContentNegotiationConfigurer configurer) {
    	Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
    	mediaTypes.put("json", MediaType.APPLICATION_JSON);
    	mediaTypes.put("xml", MediaType.APPLICATION_XML);
    Stop/Start: Still not working.

    Next I add a ContentNegotiationViewResolver to explicitly define views to be used for XML and JSON. Here I have to add the marshallingView and the
    jaxb2Marshaller as well.

    public ContentNegotiatingViewResolver setUpContentNegotiatingViewResolver() {
    	ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
    	Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
    	mediaTypes.put("json", MediaType.APPLICATION_JSON);
    	mediaTypes.put("xml", MediaType.APPLICATION_XML);
    	PathExtensionContentNegotiationStrategy pathExtensionContentNegotiationStrategy = new PathExtensionContentNegotiationStrategy(
    	ContentNegotiationManager manager = new ContentNegotiationManager(
    	List<View> defaultViews = new ArrayList<View>();
    	defaultViews.add(new MappingJacksonJsonView());
    	return resolver;
    public MarshallingView marshallingView() {
    	final MarshallingView view = new MarshallingView();
    	return view;
    public Jaxb2Marshaller jaxb2Marshaller() {
    	Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    	marshaller.setPackagesToScan(new String[] { "" });
    	return marshaller;
    At this point, the setPackagesToScan method of the jaxb2Marshaller should resolve my fear that jaxb is not aware of
    my domain class (with @XmlRootElement).

    Stop/Start: Still not working.

    Even the app knows how to "convert" the result to JSON, I decided to bring up something called HttpMessageConverter...

    public void configureMessageConverters(
    		List<HttpMessageConverter<?>> converters) {
    public Jaxb2RootElementHttpMessageConverter mappingJaxb2HttpMessageConverter() {
    	Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter = new Jaxb2RootElementHttpMessageConverter();
    	List<MediaType> mediaTypes = new ArrayList<MediaType>();
    	return jaxb2RootElementHttpMessageConverter;
    Stop/Start: Still not working.
    BTW. At this point, even JSON is not working any longer :-(

    Is it just a start order problem or some cross side effect with tiles ?
    Now, I have high hopes on you, the community ;-)