5

I've got something like this in my controller:

@RequestMapping
@ResponseBody
public HttpEntity<PagedResources<PromotionResource>> promotions(
        @PageableDefault(size = RestAPIConfig.DEFAULT_PAGE_SIZE, page = 0) Pageable pageable,
        PagedResourcesAssembler<Promotion> assembler
){

    PagedResources<PromotionResource> r = assembler.toResource(this.promoService.find(pageable), this.promoAssembler);

    return new ResponseEntity<PagedResources<PromotionResource>>(r, HttpStatus.OK);
}

If i navigate to the URL mapped to that controller method i get a 500 error with a root cause of:

com.sun.istack.internal.SAXException2: unable to marshal type "commerce.api.rest.resources.PromotionResource " as an element because it is missing an @XmlRootElement annotation 

If i throw a @XmlRootElement annotation on my resource it becomes this error:

com.sun.istack.internal.SAXException2: unable to marshal type "commerce.api.rest.resources.PromotionResource " as an element because it is not known to this context.

Everything is fine if the accept header is application/json or application/hal+json. The problem is caused only when the client (in this case chrome) is looking for application/xml (which makes sense as HATEOAS is following the clients requests. I'm using spring boot's @EnableAutoConfiguration which is adding the XML message converter to the list and thus enabling XML content types.

I'm guessing i have at least 2 options: 1. fix the jaxb error 2. remove xml as a supported content type

not sure how to do either, or maybe there's another option.

Chris DaMour
  • 3,650
  • 28
  • 37

3 Answers3

3

If you don't actually want to produce XML try using the produces attribute of the @RequestMapping annotation. Something like: @RequestMapping(produces=MediaType.APPLICATION_JSON_VALUE)

Alternatively you could exclude jaxb from you classpath or look at adding your own org.springframework.boot.autoconfigure.web.HttpMessageConverters bean to take complete control of the registered HttpMessageConverter's. See WebMvcConfigurationSupport.addDefaultHttpMessageConverters to see what Spring will add by default.

Phil Webb
  • 8,119
  • 1
  • 37
  • 37
  • i do not want to have to annotate all my actions with that – Chris DaMour May 07 '14 at 15:41
  • any change you can be more specific in your answer...i'm trying stuff but there is nightmare chain of message converters going on here...all i want to do is disable 1 specific converter without having to rewrite the world – Chris DaMour Aug 29 '14 at 19:33
  • OK, it turns out it is actually quite a pain to remove items from HttpMessageConverters with the 1.1.5 release. I've addressed this for 1.1.6 (should be released this week). See https://github.com/spring-projects/spring-boot/issues/1482 and the test case https://github.com/spring-projects/spring-boot/blob/34cbcf5e5061fc9e5accb9ea4dd6e5bb64e68b02/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersTests.java#L102-L126 – Phil Webb Sep 02 '14 at 02:39
  • that is easier, check my answer to how i ended up getting it working, although i wasn't confident it was a good solution – Chris DaMour Sep 02 '14 at 16:32
1

Not sure this is a good technique, and it looks like in 1.1.6 there's a different approach. Here's what i did:

@Configuration
public class WebMVCConfig extends WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //Remove the Jaxb2 that is automatically added because some other dependency brings it into the classpath
        List<HttpMessageConverter<?>> baseConverters = new ArrayList<HttpMessageConverter<?>>();
        super.configureMessageConverters(baseConverters);

        for(HttpMessageConverter<?> c : baseConverters){
            if(!(c instanceof Jaxb2RootElementHttpMessageConverter)){
                converters.add(c);
            }
        }
    }

}
Chris DaMour
  • 3,650
  • 28
  • 37
0

if you don't want to support XML converter, you can extend spring WebMvcConfigurer to exclude XML message converters.

@Configuration
public class WebMVCConfig extends WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(c -> c instanceof AbstractXmlHttpMessageConverter<?>);
    }

}
Dingmeng
  • 1
  • 1
  • sure today you can do it this easily...but only because of this question which prompted this enhancement see https://stackoverflow.com/questions/23480517/spring-hateoas-w-spring-boot-jaxb-marshal-error-when-returning-a-resourcest/56643017#comment40016230_23489883 – Chris DaMour Jun 19 '19 at 12:17