diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java index f30242e6ed..d1f40e29a0 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java @@ -413,12 +413,30 @@ public OpenAPI read(Class cls, } io.swagger.v3.oas.annotations.Operation apiOperation = ReflectionUtils.getAnnotation(method, io.swagger.v3.oas.annotations.Operation.class); - JsonView jsonViewAnnotation = ReflectionUtils.getAnnotation(method, JsonView.class); + JsonView jsonViewAnnotation; + JsonView jsonViewAnnotationForRequestBody; if (apiOperation != null && apiOperation.ignoreJsonView()) { jsonViewAnnotation = null; + jsonViewAnnotationForRequestBody = null; + } else { + jsonViewAnnotation = ReflectionUtils.getAnnotation(method, JsonView.class); + /* If one and only one exists, use the @JsonView annotation from the method parameter annotated + with @RequestBody. Otherwise fall back to the @JsonView annotation for the method itself. */ + jsonViewAnnotationForRequestBody = (JsonView) Arrays.stream(ReflectionUtils.getParameterAnnotations(method)) + .filter(arr -> + Arrays.stream(arr) + .anyMatch(annotation -> + annotation.annotationType() + .equals(io.swagger.v3.oas.annotations.parameters.RequestBody.class) + ) + ).flatMap(Arrays::stream) + .filter(annotation -> + annotation.annotationType() + .equals(JsonView.class) + ).reduce((a, b) -> null) + .orElse(jsonViewAnnotation); } - Operation operation = parseMethod( method, globalParameters, @@ -467,7 +485,7 @@ public OpenAPI read(Class cls, operationParameters, paramAnnotations[i], type, - jsonViewAnnotation); + jsonViewAnnotationForRequestBody); } else if (resolvedParameter.formParameter != null) { // collect params to use together as request Body formParameters.add(resolvedParameter.formParameter); @@ -499,7 +517,7 @@ public OpenAPI read(Class cls, operationParameters, paramAnnotations[i], type, - jsonViewAnnotation); + jsonViewAnnotationForRequestBody); } else if (resolvedParameter.formParameter != null) { // collect params to use together as request Body formParameters.add(resolvedParameter.formParameter); @@ -521,7 +539,7 @@ public OpenAPI read(Class cls, operationParameters, new Annotation[0], null, - jsonViewAnnotation); + jsonViewAnnotationForRequestBody); } if (operationParameters.size() > 0) { diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/JsonViewTest.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/JsonViewTest.java index 578b0b1dc1..a4b1e6162e 100644 --- a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/JsonViewTest.java +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/JsonViewTest.java @@ -6,8 +6,12 @@ import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.MediaType; + import org.testng.Assert; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,7 +20,10 @@ import java.util.Arrays; import java.util.List; +import java.util.Set; + import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.core.Response; @@ -86,6 +93,22 @@ public List getSummaries() { } } + @Path("/") + private static class CarSummaryUpdateApi { + + @PUT + @Path("/cars/summary") + @Operation(description = "Updates a car summary.") + public Response updateCarSummary( + @RequestBody(content = @Content(schema = @Schema(implementation = Car.class))) + @JsonView(View.Summary.class) + Car car) { + + return Response.noContent() + .build(); + } + } + @Path("/") private static class CarDetailApi { @@ -146,6 +169,36 @@ public void shouldSerializeTypeParameter() throws JsonProcessingException { Assert.assertFalse(openApiJson.contains("made")); Assert.assertFalse(openApiJson.contains("condition")); + reader = new Reader(new OpenAPI()); + openAPI = reader.read(CarSummaryUpdateApi.class); + Set carSummarySchemaProperties = openAPI.getComponents() + .getSchemas() + .get("Car_Summary") + .getProperties() + .keySet(); + String carSummaryUpdateApiRequestBodySchemaRef = openAPI.getPaths() + .values() + .stream() + .findAny() + .orElse(new PathItem()) + .getPut() + .getRequestBody() + .getContent() + .values() + .stream() + .findAny() + .orElse(new MediaType()) + .getSchema() + .get$ref(); + Assert.assertTrue(carSummarySchemaProperties.contains("manufacture")); + Assert.assertTrue(carSummarySchemaProperties.contains("model")); + Assert.assertTrue(carSummarySchemaProperties.contains("color")); + Assert.assertFalse(carSummarySchemaProperties.contains("price")); + Assert.assertFalse(carSummarySchemaProperties.contains("tires")); + Assert.assertFalse(carSummarySchemaProperties.contains("made")); + Assert.assertFalse(carSummarySchemaProperties.contains("condition")); + Assert.assertTrue(carSummaryUpdateApiRequestBodySchemaRef.contains("Car_Summary")); + reader = new Reader(new OpenAPI()); openAPI = reader.read(CarDetailApi.class); openApiJson = Json.mapper().writeValueAsString(openAPI);