Question

I have this Spring Java Configuration with several custom HttpMessageConverters:

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorParameter(true).
            ignoreAcceptHeader(false).
            useJaf(true).
            defaultContentType(MediaType.TEXT_HTML).
            mediaType("html", MediaType.TEXT__HTML).
            mediaType("rdf", MediaTypes.RDFXML);
}

If I query this setup with Jena I get an error:

The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers

Jena sends a request with this Accept header:

Accept: text/turtle,application/n-triples;q=0.9,application/rdf+xml;q=0.8,application/xml;q=0.7,/;q=0.5

To my understanding, application/rdf+xml, should be returned by the config above. This works perfectly as long as the type with the highest value is configured. Why doesn't Spring fall back to the 0.8-valued application/rdf+xml, because text/turtle and application/n-triples are not available?

Is there an option to activate that?

Was it helpful?

Solution

I achieve this either through defining different MVC handlers, or by reflecting on the content-type and then deciding what to return.

Defining Different Handlers

If you specify a @RequestMapping that produces some value, then that will be the type on your Content-Type header regardless of the automatic negotiation that lead your request there. You can 'force' requests to those handlers by being the only ones available to answer. I use this to return a more-specific type, but I suspect that you can also use it in order to return a more generic one as well.

@RequestMapping(value="/sparql/service", produces={"application/rdf+xml;charset=utf-8", MediaType.ALL_VALUE})
public @ResponseBody String serviceDescriptionAsRdfXml()
{
    return null; // something here
}

@RequestMapping( value="/sparql/service", produces={"text/turtle;charset=utf-8"} )
public @ResponseBody String serviceDescriptionAsTurtle( final HttpServletRequest request )
{
    return null; // something here
}

Reflecting on the Content-Type

To reflect on the type coming in, and produce something more generic, then you can actually retrieve a list of MediaType objects as part of your request, then use a ResponseEntity to define what the Content-Type will be for your result. This requires a little more thought.

@RequestMapping(value="/sparql/query", method=RequestMethod.GET)
public ResponseEntity<String> queryViaGet(@RequestHeader(value="Accept") final List<MediaType> contentTypes)
{
    MediaType.sortBySpecificityAndQuality(contentTypes);

    // Do some stuff to select your content type and generate your response
    final String results = null;
    final MediaType desiredType = null;

    // Create your REST response
    final HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentType(desiredType);
    return new ResponseEntity<String>(results, responseHeaders, HttpStatus.OK);
}

OTHER TIPS

ContentNegotiationConfigurer.mediaType(String,MediaType) applies to the request parsing and defines a mapping from the extension to the media type - if the request does not define explicit media type in the form of the Accept header but the request path ends with the specified extension that the specified media type is assumed.

Basically, ContentNegotiationConfigurer enriches (or modifies) the request data, but does not select the actual response type.

What you need is a controller that can produce either multiple media types or a multiple controllers (or multiple methods in the same controller) that produce different media types, application/rdf+xml being one of them. Spring will select that controller automatically if the application/rdf+xml is the highest common media type between the (possible enriched or modified) Accept header in the request and what your controller can actually produce.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top