Closed
Description
Describe the bug
When @Get
, using @Parameter
over the method results in duplicate of the same parameter
.
To Reproduce
What version of spring-boot you are using?
id 'org.springframework.boot' version '2.7.5'
What modules and versions of springdoc-openapi are you using?
implementation 'org.springdoc:springdoc-openapi-ui:1.6.12'
What is the actual and the expected result using OpenAPI Description (yml or json)?
actual
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"servers": [
{
"url": "http://localhost:8081",
"description": "Generated server url"
}
],
"paths": {
"/not_duplicate_param": {
"get": {
"tags": [
"sample-controller"
],
"summary": "Not Duplicate param",
"operationId": "notDuplicateParam",
"parameters": [
{
"name": "sample",
"in": "query",
"description": "sample",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/duplicate_param": {
"get": {
"tags": [
"sample-controller"
],
"summary": "Duplicate param",
"operationId": "duplicateParam",
"parameters": [
{
"name": "sample",
"in": "query",
"description": "sample",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "sample",
"in": "query",
"description": "sample",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
},
"components": {}
}
expected
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"servers": [
{
"url": "http://localhost:8081",
"description": "Generated server url"
}
],
"paths": {
"/not_duplicate_param": {
"get": {
"tags": [
"sample-controller"
],
"summary": "Not Duplicate param",
"operationId": "notDuplicateParam",
"parameters": [
{
"name": "sample",
"in": "query",
"description": "sample",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/duplicate_param": {
"get": {
"tags": [
"sample-controller"
],
"summary": "Duplicate param",
"operationId": "duplicateParam",
"parameters": [
{
"name": "sample",
"in": "query",
"description": "sample",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
},
"components": {}
}
Provide with a sample code (HelloController) or Test that reproduces the problem
Controller source code
@RestController
public class SampleController {
@GetMapping("/not_duplicate_param")
@Operation(summary = "Not Duplicate param")
public String notDuplicateParam(
@Parameter(name = "sample", required = true, description = "sample")
@RequestParam String sample) {
return "notDuplicateParam";
}
@GetMapping("/duplicate_param")
@Operation(summary = "Duplicate param")
@Parameter(name = "sample", required = true, description = "sample")
public String duplicateParam(@RequestParam String sample) {
return "duplicateParam";
}
}
Source code 1 for expected problems
Source code 2 for expected problems
private LinkedHashMap<ParameterId, Parameter> getParameterLinkedHashMap(Components components, MethodAttributes methodAttributes, List<Parameter> operationParameters, Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap) {
LinkedHashMap<ParameterId, Parameter> map = operationParameters.stream()
.collect(Collectors.toMap(
ParameterId::new,
parameter -> parameter,
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new
));
for (Map.Entry<String, io.swagger.v3.oas.annotations.Parameter> entry : parametersDocMap.entrySet()) {
ParameterId parameterId = new ParameterId(entry.getValue());
if (entry.getKey() != null && !map.containsKey(parameterId) && !entry.getValue().hidden()) {
//Convert
Parameter parameter = parameterBuilder.buildParameterFromDoc(entry.getValue(), components,
methodAttributes.getJsonViewAnnotation(), methodAttributes.getLocale());
map.put(parameterId, parameter);
}
}
getHeaders(methodAttributes, map);
map.forEach((parameterId, parameter) -> {
if(StringUtils.isBlank(parameter.getIn()) && StringUtils.isBlank(parameter.get$ref()))
parameter.setIn(ParameterIn.QUERY.toString());
});
return map;
}
Expected behavior
When using @Parameter
over the method, io.swagger.v3.oas.annotations.parameter
is entered in the argument parametersDocMap
.
After that, when comparing the values of condition if(!map.containsKey(entry.getKey()))
, it is compared with hashCode of ParameterId
, and even though it is the same ParameterId
, it is classified as different ParameterId
.
Hash code for "ParameterId.java"
Screenshots
@RestController
public class SampleController {
@GetMapping("/not_duplicate_param")
@Operation(summary = "Not Duplicate param")
public String notDuplicateParam(
@Parameter(name = "sample", required = true, description = "sample")
@RequestParam String sample) {
return "notDuplicateParam";
}
@GetMapping("/duplicate_param")
@Operation(summary = "Duplicate param")
@Parameter(name = "sample", required = true, description = "sample")
public String duplicateParam(@RequestParam String sample) {
return "duplicateParam";
}
}