Skip to content

When @Get, using @Parameter over the method results in duplicate of the same parameter #1901

Closed
@mskangg

Description

@mskangg

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";
    }
}

image

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions