Skip to content

Custom Requestmapping consumes responses #1546

Closed
@T-Developer1

Description

@T-Developer1

What i am trying to do

I am trying to set a specific consumes / produces Type for multiple Mappings.

I know that i can set them like this:

@PostMapping( "/testPostMapping", consumes = { MediaType.APPLICATION_CBOR_VALUE } )
but then i have to add consumes and produces to every Mapping method.

I have an Controller Class which sets produces for all my RequestMappings

@RequestMapping( produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE } )
public abstract class Controller
{

}

I extend this Controller and have some Mappings inside it.

public class ExampleController extends Controller
{

   @GetMapping( value = "/getTest" )
   public @ResponseBody ResponseEntity<String> testGetMapping()
   {
      return new ResponseEntity<String>( "TestString", HttpStatus.OK );
   }

   @PostMapping( "/testPostMapping" )
   public @ResponseBody ResponseEntity<String> testPostMapping( String testString )
   {
      return new ResponseEntity<String>( "TestString", HttpStatus.OK );

   }

}

Now i only want to set the consumes Type to the PostMapping.

What i already tried

I already tried to add The @ApiResponse Annotation

@ApiResponses( value = {
                         @ApiResponse( responseCode = "200", content = @Content( mediaType = MediaType.APPLICATION_XML_VALUE ) ) } )

public @interface DefaultProduces
{
   String[] produces() default {

                                 MediaType.APPLICATION_XML_VALUE };
}

but this will override the content Type of my Requests

if i add this to two @PostMappings , and one Returns a String the other one Returns an HTML element
@ApiResponse will override the schema type information

Without the ApiResponse Annotation

           "content": {
              "*/*": {
                "schema": {
                  "type": "string"
                }
              }

With the ApiResponse Annotation

"content": {
              "application/xml": {
                
              }

How i attampted it

I made my own Annotations

@Target( { ElementType.TYPE, ElementType.METHOD } )
@Retention( RetentionPolicy.RUNTIME )
@Inherited
public @interface DefaultProduces
{
   String[] produces() default {

                                 MediaType.TEXT_HTML_VALUE };
}

and extended the WebMvcConfig RequestMappingHandler

   @Override
   protected RequestMappingHandlerMapping createRequestMappingHandlerMapping()
   {
      return new ExtendedRequestMappingHandlerMapping();
   }

So that if i add @DefaultProduces to a RequestMapping it will have the MediaTypes which i added there

I overrode the RequestMappingInfo with my customized infos.

But OpenAPI does not take the Informations from RequestMappingInfo .

Describe the solution you'd like

Is there a way to let openAPI get his Informations from the RequestMappingInfo.

Or is there an Annotation like Request @ApiResponse where i can only set the consumes or produces Types without chaning anything else.

** TestProject **

In my TestProject is a Controller with a PostMapping like this

   @DefaultConsumes
   @PostMapping( value = "/testPostMapping" )
   public @ResponseBody ResponseEntity<String> testPostMapping( String testString )
   {
      return new ResponseEntity<String>( "TestString", HttpStatus.OK );
   }

My annotation DefaultConsomes makes the PostMapping only accapt text/plain

The OpenAPI Json still says that the content is /

 "content": {
              "*/*": {
                "schema": {
                  "type": "string"
                }
              }

which leads to the following Curl request in Swagger-ui

`curl -X 'POST' \
  'http://localhost:8080/testPostMapping' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '"string"'`

The PostMapping will response with

{
  "timestamp": 1647005196793,
  "status": 406,
  "error": "Not Acceptable",
  "path": "/testPostMapping"
}

If text/plain is set it is working.

curl -o - -X 'POST' \
  'http://localhost:8080/testPostMapping' \
  -H 'accept: text/plain' \
  -H 'Content-Type: application/json' \
  -d '"string"'

should output "TestString"

Here is a basic Project with my issue

https://github.com/T-Developer1/SpringdocCustomAnnotationSample

Additional Informations

In OpenApiResources the consumes and Produces are correct

String[] produces = requestMappingInfo.getProducesCondition().getProducibleMediaTypes().stream().map(MimeType::toString).toArray(String[]::new);
String[] consumes = requestMappingInfo.getConsumesCondition().getConsumableMediaTypes().stream().map(MimeType::toString).toArray(String[]::new);

but the Informations get lost after that
In AbstractOpenApiResources produces and consumes are null

String[] methodConsumes = routerOperation.getConsumes();
String[] methodProduces = routerOperation.getProduces();

And even if you change the value there, it will be overriden again in MethodAttribute

PostMapping reqPostMappingMethod = AnnotatedElementUtils.findMergedAnnotation(method, PostMapping.class);
if (reqPostMappingMethod != null) {
fillMethods(reqPostMappingMethod.produces(), reqPostMappingMethod.consumes(), reqPostMappingMethod.headers());
return;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions