What Determines @ResponseBody’s Default Return Format in Spring MVC?

In Spring MVC, the default data format returned by @ResponseBody depends on the client’s Accept header, and the framework selects an appropriate HttpMessageConverter through RequestResponseBodyMethodProcessor, which evaluates acceptable and producible media types to produce JSON, XML, or other formats.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
What Determines @ResponseBody’s Default Return Format in Spring MVC?

Background

@ResponseBody default return format when backend does not specify produces MediaType?

@Controller
public class DemoController {
  @ResponseBody
  @GetMapping(value = "/demo")
  public DemoVO demo() {
    return new DemoVO("lengleng", "123456");
  }
}

Search results show that @ResponseBody converts a Java object to JSON.

Correct Answer

We first publish the correct answer.

The output format of @ResponseBody, by default, is determined by the client’s Accept request header.

Source Code Analysis

RequestResponseBodyMethodProcessor

public class RequestResponseBodyMethodProcessor {
  // handle @ResponseBody annotated methods
  @Override
  public boolean supportsReturnType(MethodParameter returnType) {
    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
            returnType.hasMethodAnnotation(ResponseBody.class));
  }
  // handle return value
  @Override
  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
                                ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
    // write with converters
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
  }
}

writeWithMessageConverters

protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
                        ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
  HttpServletRequest request = inputMessage.getServletRequest();
  // Get Accept header media types
  List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
  // Get producible media types declared by the controller
  List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
  // Determine media types to use
  List<MediaType> mediaTypesToUse = new ArrayList<>();
  for (MediaType requestedType : acceptableTypes) {
    for (MediaType producibleType : producibleTypes) {
      if (requestedType.isCompatibleWith(producibleType)) {
        mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
      }
    }
  }
  // Sort by specificity and quality
  MediaType.sortBySpecificityAndQuality(mediaTypesToUse);

  for (MediaType mediaType : mediaTypesToUse) {
    if (mediaType.isConcrete()) {
      selectedMediaType = mediaType;
      break;
    } else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
      selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
      break;
    }
  }

  selectedMediaType = selectedMediaType.removeQualityValue();
  // Find a suitable HttpMessageConverter and write the body
  for (HttpMessageConverter<?> converter : this.messageConverters) {
    GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
        (GenericHttpMessageConverter<?>) converter : null);
    if (genericConverter != null ?
        genericConverter.canWrite(targetType, valueType, selectedMediaType) :
        converter.canWrite(valueType, selectedMediaType)) {
      body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
        (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
        inputMessage, outputMessage);
      return;
    }
  }
}

Why Study This Issue

When upgrading to spring cloud alibaba 2.2.1, the sentinel module brings in additional dependencies.

If the dataformat jar appears, RestTemplate adds the following media types to the default Accept header:

application/xml | text/xml | application/*+xml

public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) {
  super(objectMapper,
        new MediaType("application", "xml", StandardCharsets.UTF_8),
        new MediaType("text", "xml", StandardCharsets.UTF_8),
        new MediaType("application", "*+xml", StandardCharsets.UTF_8));
  Assert.isInstanceOf(XmlMapper.class, objectMapper, "XmlMapper required");
}

When using RestTemplate without specifying Accept, the response may be XML, preventing a smooth upgrade.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring MVCResponseBodyAccept HeaderHttpMessageConverter
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.