diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java index bb2e4b69a..dbb545a98 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/models/MethodAttributes.java @@ -25,6 +25,8 @@ package org.springdoc.core.models; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; @@ -32,11 +34,13 @@ import com.fasterxml.jackson.annotation.JsonView; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -275,28 +279,38 @@ else if (reqMappingClass != null) { * @param headers the headers */ private void fillMethods(String[] produces, String[] consumes, String[] headers) { - if (ArrayUtils.isEmpty(methodProduces)) { - if (ArrayUtils.isNotEmpty(produces)) - methodProduces = produces; - else if (ArrayUtils.isNotEmpty(classProduces)) - methodProduces = classProduces; - else - methodProduces = new String[] { defaultProducesMediaType }; - } - - if (ArrayUtils.isEmpty(methodConsumes)) { - if (ArrayUtils.isNotEmpty(consumes)) - methodConsumes = consumes; - else if (ArrayUtils.isNotEmpty(classConsumes)) - methodConsumes = classConsumes; - else - methodConsumes = new String[] { defaultConsumesMediaType }; - } - - if (CollectionUtils.isEmpty(this.headers)) - setHeaders(headers); + if (ArrayUtils.isNotEmpty(produces)) { + methodProduces = mergeArrays(methodProduces, produces); + } else if (ArrayUtils.isNotEmpty(classProduces)) { + methodProduces = mergeArrays(methodProduces, classProduces); + } else if (ArrayUtils.isEmpty(methodProduces)) { + methodProduces = new String[] {defaultProducesMediaType}; + } + + if (ArrayUtils.isNotEmpty(consumes)) { + methodConsumes = mergeArrays(methodConsumes, consumes); + } else if (ArrayUtils.isNotEmpty(classConsumes)) { + methodConsumes = mergeArrays(methodConsumes, classConsumes); + } else if (ArrayUtils.isEmpty(methodConsumes)) { + methodConsumes = new String[] {defaultConsumesMediaType}; + } + + setHeaders(headers); } + /** + * Merge string arrays into one array with unique values + * + * @param array1 the array1 + * @param array2 the array2 + * @return the string [ ] + */ + private String[] mergeArrays(@Nullable String[] array1, String[] array2) { + Set uniqueValues = array1 == null ? new HashSet<>() : Arrays.stream(array1).collect(Collectors.toSet()); + uniqueValues.addAll(Arrays.asList(array2)); + return uniqueValues.toArray(new String[0]); + } + /** * Is method overloaded boolean. * diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java new file mode 100644 index 000000000..0b2b37d5c --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/HelloController.java @@ -0,0 +1,42 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app219; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(value = "/api", produces = {"application/xml"}, consumes = {"application/json"}) +public class HelloController { + + @RequestMapping(value = "/testpost", method = RequestMethod.POST, produces = {"application/json"}, + consumes = {"application/json;charset=UTF-8", "application/json; charset=UTF-8"}) + public ResponseEntity testpost(@RequestBody TestObject dto) { + return ResponseEntity.ok(dto); + } +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java new file mode 100644 index 000000000..a6ec97f84 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/SpringDocApp219Test.java @@ -0,0 +1,36 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app219; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.context.ActiveProfiles; +import test.org.springdoc.api.v30.AbstractSpringDocV30Test; + +@ActiveProfiles("219") +public class SpringDocApp219Test extends AbstractSpringDocV30Test { + + @SpringBootApplication + static class SpringDocTestApp {} +} diff --git a/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java new file mode 100644 index 000000000..ca336cca3 --- /dev/null +++ b/springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/app219/TestObject.java @@ -0,0 +1,49 @@ +/* + * + * * + * * * + * * * * + * * * * * Copyright 2019-2022 the original author or authors. + * * * * * + * * * * * Licensed under the Apache License, Version 2.0 (the "License"); + * * * * * you may not use this file except in compliance with the License. + * * * * * You may obtain a copy of the License at + * * * * * + * * * * * https://www.apache.org/licenses/LICENSE-2.0 + * * * * * + * * * * * Unless required by applicable law or agreed to in writing, software + * * * * * distributed under the License is distributed on an "AS IS" BASIS, + * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * * * * See the License for the specific language governing permissions and + * * * * * limitations under the License. + * * * * + * * * + * * + * + */ + +package test.org.springdoc.api.v30.app219; + +import java.time.LocalDateTime; + +public class TestObject { + public String stringValue; + + public LocalDateTime localDateTime; + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } +}