6

I want to return a simple plain text string as follows:

@RestController 
@RequestMapping("/test")
public class TestController {
    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(value = "/my", method = RequestMethod.GET, produces="text/plain")
    public String test() {
        return "OK";
    }

Problem: I also have a global ContentNegotiation filter as follows:

@Configuration
public class ContentNegotiationAdapter extends WebMvcConfigurerAdapter {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false)
                .favorParameter(true)
                .ignoreAcceptHeader(true)
                .useJaf(false)
                .defaultContentType(MediaType.APPLICATION_XML);
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
    }
}

Result: whenever I access the spring controller, I'm getting the error:

Could not find acceptable representation

Question: how can I force the controller to return plain text, even though only XML was configured within content negotation (which I have to keep)?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
membersound
  • 81,582
  • 193
  • 585
  • 1,120

4 Answers4

3

If you remove produces="text/plain" from the mapping, it returns plain text but the header is set to "application/xml". This is probably not desirable. I tested with the latest version of Spring Boot.

If you are using the version of Spring >= 4.1.2, you can try to use defaultContentTypeStrategy instead of defaultContentType, to set the correct content type in the header:

   configurer.favorPathExtension(false)
            .favorParameter(true)
            .ignoreAcceptHeader(true)
            .useJaf(false)
            .defaultContentTypeStrategy(new ContentNegotiationStrategy() {
                @Override
                public List<MediaType> resolveMediaTypes(NativeWebRequest nativeWebRequest) throws
                        HttpMediaTypeNotAcceptableException {
                    System.out.println("Description:"+nativeWebRequest.getDescription(false));
                    if (nativeWebRequest.getDescription(false).endsWith("/test/my")) {
                        return Collections.singletonList(MediaType.TEXT_PLAIN);
                    }
                    else {
                        return Collections.singletonList(MediaType.APPLICATION_XML);
                    }
                }
            })
            //.defaultContentType(MediaType.APPLICATION_XML)
;
jny
  • 8,007
  • 3
  • 37
  • 56
1

First Way

@GetMapping(value = "/", produces = MediaType.TEXT_PLAIN_VALUE)
public @ResponseBody
String getResponseAsText() {

    return "Text Message Here";
}

Second Way

@GetMapping(value = "/")
public ResponseEntity<String> getResponseAsText() {

    var httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(new MediaType("text", "plain", StandardCharsets.UTF_8));

    return new ResponseEntity<>("Text Message here", httpHeaders, HttpStatus.OK);
}
Amir Shaikh
  • 159
  • 1
  • 4
  • Those two methods aren't doing the same... Anything in `@GetMapping` (or `@RequestMapping`) is used, as the name implies, for mapping a request to a controller method. It does nothing to enforcing the content type being returned (produces actually accepts an array of values so you can have different methods for the same URL producing different content, but it isn't enforcing anything). – M. Deinum Sep 29 '22 at 13:13
  • `httpHeaders.setContentType(new MediaType("text", "plain", StandardCharsets.UTF_8))` is used when you want to manually set the content type for a specific HTTP response. `@Produces(MediaType.TEXT_PLAIN)` is an annotation that is used in the context of frameworks like JAX-RS or Spring Web's MVC to declare the media type that a resource method (e.g., a controller method) produces. Both approaches achieve the same result of setting the HTTP response content type to plain text. The choice between them depends on the specific requirements and the framework being used. – Amir Shaikh May 23 '23 at 05:58
  • `@Produces` won't work with Spring MVC, so suggesting to do that won't work. – M. Deinum May 23 '23 at 06:09
  • Indeed, you are correct. I elaborated on an alternative approach(Second Way) to accomplish content negotiation in Spring MVC. thanks ... – Amir Shaikh May 25 '23 at 06:04
-1

If I recall well, you can annotate the method with @ResponseBody and it will return plain text.

Check this

Fustigador
  • 6,339
  • 12
  • 59
  • 115
-2

You need to specify @ResponseBody annotation for your test method like:

public @ResponseBody String test(){}
Shekhar Khairnar
  • 2,643
  • 3
  • 26
  • 44