Backend Development 5 min read

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?

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

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

<code>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);
  }
}
</code>

writeWithMessageConverters

<code>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;
    }
  }
}
</code>

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

<code>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");
}
</code>

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

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

login 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.