Spring Framework
  1. Spring Framework
  2. SPR-6702

Explicitly set response Content-Type in @ResponseBody

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: None
    • Fix Version/s: 3.1 M2
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      It would be useful to override the default content-type written by the HttpMessageConverters in the @ResponseBody annotation. Something like:

      @ResponseBody("foo/bar")
      public String myHandlerMethod() {
        return "myFooBar";
      }
      

        Issue Links

          Activity

          Hide
          Rossen Stoyanchev added a comment -

          @Cédric, your example would actually work:

          @RequestMapping(value = "/foo/bar", produces = "text/html")
          @ResponseBody
          public String handle() { return "whatever"; }
          

          A single MessageConverter is configured that accepts String and can produce "text/plain" and "text/html".

          If a browser sends Accept "/", the result would be "text/html". That's because a produces is used not only to match the method to the request but it is also the top preference for the actual content type to write out. As opposed to the default media type of a converter or the order the converters.

          Hence I do think SPR-7353 addresses the motivations listed for this issue.

          Show
          Rossen Stoyanchev added a comment - @Cédric, your example would actually work: @RequestMapping(value = "/foo/bar" , produces = "text/html" ) @ResponseBody public String handle() { return "whatever" ; } A single MessageConverter is configured that accepts String and can produce "text/plain" and "text/html". If a browser sends Accept " / ", the result would be "text/html". That's because a produces is used not only to match the method to the request but it is also the top preference for the actual content type to write out. As opposed to the default media type of a converter or the order the converters. Hence I do think SPR-7353 addresses the motivations listed for this issue.
          Hide
          Cédric Laruelle added a comment -

          Hi Rossen.
          Thanks for taking time to look into this.

          In my example, I have a single message converter, so I'm not using the default Spring MessageConverter that accepts String.
          Actually, I think you make a mistake saying

          it is also the top preference for the actual content type to write out

          . Could you please let me know where in the code produces is used to determine the output content type ? As far as I can see, in AnnotationMethodHandlerAdapter,

          List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
          if (getMessageConverters() != null) {
          	for (MediaType acceptedMediaType : acceptedMediaTypes) {
          		for (HttpMessageConverter messageConverter : getMessageConverters()) {
          			if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {
          				messageConverter.write(returnValue, acceptedMediaType, outputMessage);
          				if (logger.isDebugEnabled()) {
          					MediaType contentType = outputMessage.getHeaders().getContentType();
          					if (contentType == null) {
          						contentType = acceptedMediaType;
          					}
          					logger.debug("Written [" + returnValue + "] as \"" + contentType +
          							"\" using [" + messageConverter + "]");
          				}
          				this.responseArgumentUsed = true;
          				return;
          			}
          		}
          	}
          	for (HttpMessageConverter messageConverter : messageConverters) {
          		allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
          	}
          }
          

          starting line 1019

          So as far as I can see, the output content type only depends on :

          • The return type which defines the converter to use
          • The accept headers
          • The supported media types for the converter
          Show
          Cédric Laruelle added a comment - Hi Rossen. Thanks for taking time to look into this. In my example, I have a single message converter, so I'm not using the default Spring MessageConverter that accepts String. Actually, I think you make a mistake saying it is also the top preference for the actual content type to write out . Could you please let me know where in the code produces is used to determine the output content type ? As far as I can see, in AnnotationMethodHandlerAdapter, List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); if (getMessageConverters() != null ) { for (MediaType acceptedMediaType : acceptedMediaTypes) { for (HttpMessageConverter messageConverter : getMessageConverters()) { if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { messageConverter.write(returnValue, acceptedMediaType, outputMessage); if (logger.isDebugEnabled()) { MediaType contentType = outputMessage.getHeaders().getContentType(); if (contentType == null ) { contentType = acceptedMediaType; } logger.debug( "Written [" + returnValue + "] as \" " + contentType + "\" using [ " + messageConverter + " ]"); } this .responseArgumentUsed = true ; return ; } } } for (HttpMessageConverter messageConverter : messageConverters) { allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); } } starting line 1019 So as far as I can see, the output content type only depends on : The return type which defines the converter to use The accept headers The supported media types for the converter
          Hide
          Rossen Stoyanchev added a comment -

          Ah, I see now where the difference comes from. The produces/consumes @RequestMapping conditions (along with all other Spring 3.1 improvements related to annotates controllers) are only implemented in the new @MVC support classes. You'll find pointers to the details in the What's New in 3.1 section of the reference docs.

          In short the AnnotationMethodHandlerAdapter doesn't contain this functionality. The RequestMappingHandlerAdapter does and the code you wanted to see is in AbstractMessageConverterMethodProcessor#writeWithMessageConverters.

          Show
          Rossen Stoyanchev added a comment - Ah, I see now where the difference comes from. The produces/consumes @RequestMapping conditions (along with all other Spring 3.1 improvements related to annotates controllers) are only implemented in the new @MVC support classes. You'll find pointers to the details in the What's New in 3.1 section of the reference docs. In short the AnnotationMethodHandlerAdapter doesn't contain this functionality. The RequestMappingHandlerAdapter does and the code you wanted to see is in AbstractMessageConverterMethodProcessor#writeWithMessageConverters.
          Hide
          Cédric Laruelle added a comment -

          Thanks for that answer.
          You're right ! I'm sorry for my mistake, for some reason, I did not make the connection between the new @MVC support classes and the produces/consumes.
          Thanks again for your time !

          Show
          Cédric Laruelle added a comment - Thanks for that answer. You're right ! I'm sorry for my mistake, for some reason, I did not make the connection between the new @MVC support classes and the produces/consumes. Thanks again for your time !
          Hide
          Rossen Stoyanchev added a comment -

          No problem!

          Show
          Rossen Stoyanchev added a comment - No problem!

            People

            • Assignee:
              Rossen Stoyanchev
              Reporter:
              Arjen Poutsma
              Last updater:
              Trevor Marshall
            • Votes:
              10 Vote for this issue
              Watchers:
              15 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                2 years, 13 weeks ago