Skip to content

Commit

Permalink
When @get, using @parameter over the method results in duplicate of t…
Browse files Browse the repository at this point in the history
…he same parameter. Fixes #1901.
  • Loading branch information
bnasslahsen committed Oct 22, 2022
1 parent 1c63f0f commit 7426a96
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ public void buildCommonParameters(OpenAPI openAPI, RequestMethod requestMethod,
Class<?> domainType = dataRestRepository.getDomainType();
for (MethodParameter methodParameter : parameters) {
final String pName = methodParameter.getParameterName();
ParameterInfo parameterInfo = new ParameterInfo(pName, methodParameter, parameterBuilder);
io.swagger.v3.oas.annotations.Parameter parameterDoc = AnnotatedElementUtils.findMergedAnnotation(
AnnotatedElementUtils.forAnnotations(methodParameter.getParameterAnnotations()),
io.swagger.v3.oas.annotations.Parameter.class);
ParameterInfo parameterInfo = new ParameterInfo(pName, methodParameter, parameterBuilder,parameterDoc);
if (isParamToIgnore(methodParameter)) {
if (PersistentEntityResource.class.equals(methodParameter.getParameterType())) {
Schema<?> schema = SpringDocAnnotationsUtils.resolveSchemaFromType(domainType, openAPI.getComponents(), null, methodParameter.getParameterAnnotations());
Expand All @@ -165,9 +168,6 @@ else if (methodParameter.getParameterAnnotation(BackendId.class) != null) {
parameterInfo.setParameterModel(new Parameter().name("id").in(ParameterIn.PATH.toString()).schema(new StringSchema()));
}
Parameter parameter = null;
io.swagger.v3.oas.annotations.Parameter parameterDoc = AnnotatedElementUtils.findMergedAnnotation(
AnnotatedElementUtils.forAnnotations(methodParameter.getParameterAnnotations()),
io.swagger.v3.oas.annotations.Parameter.class);
if (parameterDoc != null) {
if (parameterDoc.hidden() || parameterDoc.schema().hidden())
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,19 @@ public ParameterId(Parameter parameter) {
*/
public ParameterId(io.swagger.v3.oas.annotations.Parameter parameter) {
this.pName = parameter.name();
this.paramType = parameter.in().toString();
this.$ref = parameter.ref();
this.paramType = StringUtils.isNotBlank(parameter.in().toString()) ? parameter.in().toString():null;
this.$ref = StringUtils.isNotBlank(parameter.ref()) ? parameter.ref():null;
}

/**
* Instantiates a new Parameter id.
*
* @param pName the p name
* @param paramType the param type
*/
public ParameterId(String pName, String paramType) {
this.pName = pName;
this.paramType =paramType;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package org.springdoc.core.models;

import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -79,6 +80,12 @@ public class ParameterInfo {
*/
private boolean requestPart;


/**
* The Parameter id.
*/
private ParameterId parameterId;

/**
* The constant LOGGER.
*/
Expand All @@ -89,8 +96,9 @@ public class ParameterInfo {
* @param pName the parameter name
* @param methodParameter the method parameter
* @param genericParameterService the parameter builder
* @param parameterAnnotation the parameter annotation
*/
public ParameterInfo(String pName, MethodParameter methodParameter, GenericParameterService genericParameterService) {
public ParameterInfo(String pName, MethodParameter methodParameter, GenericParameterService genericParameterService, Parameter parameterAnnotation) {
RequestHeader requestHeader = methodParameter.getParameterAnnotation(RequestHeader.class);
RequestParam requestParam = methodParameter.getParameterAnnotation(RequestParam.class);
PathVariable pathVar = methodParameter.getParameterAnnotation(PathVariable.class);
Expand Down Expand Up @@ -126,6 +134,16 @@ else if (cookieValue != null)
}

this.required = this.required && !methodParameter.isOptional();
if (parameterAnnotation != null) {
this.parameterId = new ParameterId(parameterAnnotation);
if (StringUtils.isBlank(parameterId.getpName()))
this.parameterId.setpName(this.pName);
if (StringUtils.isBlank(parameterId.getParamType()))
this.parameterId.setParamType(this.paramType);
}
else
this.parameterId = new ParameterId(this.pName, paramType);

}

/**
Expand Down Expand Up @@ -297,4 +315,23 @@ public boolean isRequestPart() {
public void setRequestPart(boolean requestPart) {
this.requestPart = requestPart;
}


/**
* Gets parameter id.
*
* @return the parameter id
*/
public ParameterId getParameterId() {
return parameterId;
}

/**
* Sets parameter id.
*
* @param parameterId the parameter id
*/
public void setParameterId(ParameterId parameterId) {
this.parameterId = parameterId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
parameters = DelegatingMethodParameter.customize(pNames, parameters, parameterBuilder.getDelegatingMethodParameterCustomizer(), this.defaultFlatParamObject);
RequestBodyInfo requestBodyInfo = new RequestBodyInfo();
List<Parameter> operationParameters = (operation.getParameters() != null) ? operation.getParameters() : new ArrayList<>();
Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(handlerMethod.getMethod());
Map<ParameterId, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(handlerMethod.getMethod());
Components components = openAPI.getComponents();

JavadocProvider javadocProvider = operationService.getJavadocProvider();
Expand All @@ -274,10 +274,10 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
io.swagger.v3.oas.annotations.Parameter.class);

final String pName = methodParameter.getParameterName();
ParameterInfo parameterInfo = new ParameterInfo(pName, methodParameter, parameterBuilder);
ParameterInfo parameterInfo = new ParameterInfo(pName, methodParameter, parameterBuilder, parameterDoc);

if (parameterDoc == null)
parameterDoc = parametersDocMap.get(parameterInfo.getpName());
parameterDoc = parametersDocMap.get(parameterInfo.getParameterId());

if (parameterDoc == null) {
io.swagger.v3.oas.annotations.media.Schema schema = AnnotatedElementUtils.findMergedAnnotation(
Expand Down Expand Up @@ -364,35 +364,43 @@ else if (!RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1.
* @param parametersDocMap the parameters doc map
* @return the parameter linked hash map
*/
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);
private LinkedHashMap<ParameterId, Parameter> getParameterLinkedHashMap(Components components, MethodAttributes methodAttributes, List<Parameter> operationParameters, Map<ParameterId, 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<ParameterId, io.swagger.v3.oas.annotations.Parameter> entry : parametersDocMap.entrySet()) {
ParameterId parameterId = entry.getKey();
if (parameterId != null && !map.containsKey(parameterId) && !entry.getValue().hidden()) {
Parameter parameter = parameterBuilder.buildParameterFromDoc(entry.getValue(), components, methodAttributes.getJsonViewAnnotation(), methodAttributes.getLocale());
//proceed with the merge if possible
if (map.containsKey(parameterId)) {
GenericParameterService.mergeParameter(map.get(parameterId), parameter);
map.put(parameterId, parameter);
}
else {
long mumParamsWithName = map.keySet().stream().filter(parameterId1 -> parameterId.getpName().equals(parameterId1.getpName())).count();
long mumParamsDocWithName = parametersDocMap.keySet().stream().filter(parameterId1 -> parameterId.getpName().equals(parameterId1.getpName())).count();
if (mumParamsWithName == 1 && mumParamsDocWithName == 1) {
Optional<ParameterId> parameterIdWithSameNameOptional = map.keySet().stream().filter(parameterId1 -> parameterId.getpName().equals(parameterId1.getpName())).findAny();
parameterIdWithSameNameOptional.ifPresent(parameterIdWithSameName -> {
GenericParameterService.mergeParameter(map.get(parameterIdWithSameName), parameter);
map.put(parameterIdWithSameName, parameter);
});
}
else
map.put(parameterId, parameter);
}
}
}

getHeaders(methodAttributes, map);
map.forEach((parameterId, parameter) -> {
if(StringUtils.isBlank(parameter.getIn()) && StringUtils.isBlank(parameter.get$ref()))
getHeaders(methodAttributes, map); map.forEach((parameterId, parameter) -> {
if (StringUtils.isBlank(parameter.getIn()) && StringUtils.isBlank(parameter.get$ref()))
parameter.setIn(ParameterIn.QUERY.toString());
});
return map;
}); return map;
}


/**
* Gets headers.
*
Expand Down Expand Up @@ -650,34 +658,22 @@ public RequestBodyService getRequestBodyBuilder() {
* @param method the method
* @return the api parameters
*/
private Map<String, io.swagger.v3.oas.annotations.Parameter> getApiParameters(Method method) {
private Map<ParameterId, io.swagger.v3.oas.annotations.Parameter> getApiParameters(Method method) {
Class<?> declaringClass = method.getDeclaringClass();

Set<io.swagger.v3.oas.annotations.Parameters> apiParametersDoc = AnnotatedElementUtils
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameters.class);
LinkedHashMap<String, io.swagger.v3.oas.annotations.Parameter> apiParametersMap = apiParametersDoc.stream()
.flatMap(x -> Stream.of(x.value())).collect(Collectors.toMap(io.swagger.v3.oas.annotations.Parameter::name, x -> x, (e1, e2) -> e2,
LinkedHashMap::new));

Set<io.swagger.v3.oas.annotations.Parameters> apiParametersDocDeclaringClass = AnnotatedElementUtils
.findAllMergedAnnotations(declaringClass, io.swagger.v3.oas.annotations.Parameters.class);
LinkedHashMap<String, io.swagger.v3.oas.annotations.Parameter> apiParametersDocDeclaringClassMap = apiParametersDocDeclaringClass.stream()
.flatMap(x -> Stream.of(x.value())).collect(Collectors.toMap(io.swagger.v3.oas.annotations.Parameter::name, x -> x, (e1, e2) -> e2,
LinkedHashMap::new));
Set<io.swagger.v3.oas.annotations.Parameters> apiParametersDoc = AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameters.class);
LinkedHashMap<ParameterId, io.swagger.v3.oas.annotations.Parameter> apiParametersMap = apiParametersDoc.stream().flatMap(x -> Stream.of(x.value())).collect(Collectors.toMap(ParameterId::new, x -> x, (e1, e2) -> e2, LinkedHashMap::new));

Set<io.swagger.v3.oas.annotations.Parameters> apiParametersDocDeclaringClass = AnnotatedElementUtils.findAllMergedAnnotations(declaringClass, io.swagger.v3.oas.annotations.Parameters.class);
LinkedHashMap<ParameterId, io.swagger.v3.oas.annotations.Parameter> apiParametersDocDeclaringClassMap = apiParametersDocDeclaringClass.stream().flatMap(x -> Stream.of(x.value())).collect(Collectors.toMap(ParameterId::new, x -> x, (e1, e2) -> e2, LinkedHashMap::new));
apiParametersMap.putAll(apiParametersDocDeclaringClassMap);

Set<io.swagger.v3.oas.annotations.Parameter> apiParameterDoc = AnnotatedElementUtils
.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameter.class);
LinkedHashMap<String, io.swagger.v3.oas.annotations.Parameter> apiParameterDocMap = apiParameterDoc.stream()
.collect(Collectors.toMap(io.swagger.v3.oas.annotations.Parameter::name, x -> x, (e1, e2) -> e2,
LinkedHashMap::new));
Set<io.swagger.v3.oas.annotations.Parameter> apiParameterDoc = AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.Parameter.class);
LinkedHashMap<ParameterId, io.swagger.v3.oas.annotations.Parameter> apiParameterDocMap = apiParameterDoc.stream().collect(Collectors.toMap(ParameterId::new, x -> x, (e1, e2) -> e2, LinkedHashMap::new));
apiParametersMap.putAll(apiParameterDocMap);

Set<io.swagger.v3.oas.annotations.Parameter> apiParameterDocDeclaringClass = AnnotatedElementUtils
.findAllMergedAnnotations(declaringClass, io.swagger.v3.oas.annotations.Parameter.class);
LinkedHashMap<String, io.swagger.v3.oas.annotations.Parameter> apiParameterDocDeclaringClassMap = apiParameterDocDeclaringClass.stream()
.collect(Collectors.toMap(io.swagger.v3.oas.annotations.Parameter::name, x -> x, (e1, e2) -> e2,
LinkedHashMap::new));
Set<io.swagger.v3.oas.annotations.Parameter> apiParameterDocDeclaringClass = AnnotatedElementUtils.findAllMergedAnnotations(declaringClass, io.swagger.v3.oas.annotations.Parameter.class);
LinkedHashMap<ParameterId, io.swagger.v3.oas.annotations.Parameter> apiParameterDocDeclaringClassMap = apiParameterDocDeclaringClass.stream().collect(Collectors.toMap(ParameterId::new, x -> x, (e1, e2) -> e2, LinkedHashMap::new));
apiParametersMap.putAll(apiParameterDocDeclaringClassMap);

return apiParametersMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public static Parameter mergeParameter(List<Parameter> existingParamDoc, Paramet
* @param paramCalcul the param calcul
* @param paramDoc the param doc
*/
private static void mergeParameter(Parameter paramCalcul, Parameter paramDoc) {
public static void mergeParameter(Parameter paramCalcul, Parameter paramDoc) {
if (StringUtils.isBlank(paramDoc.getDescription()))
paramDoc.setDescription(paramCalcul.getDescription());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


Expand Down Expand Up @@ -69,4 +70,28 @@ void list(@RequestHeader(value = "access_token", required = false)
}
public static class Item {
}


@GetMapping("/duplicate_param")
@Operation(summary = "Duplicate param")
@Parameter(name = "sample", required = true, in = ParameterIn.HEADER, description = "sample Header")
@Parameter(name = "sample", required = true, in = ParameterIn.QUERY, description = "sample query")
public String duplicateParam(@RequestParam String sample, @RequestHeader("sample") String sampleHeader) {
return "duplicateParam";
}

@GetMapping("/duplicate_param2")
@Operation(summary = "Duplicate param")
@Parameter(name = "sample", required = true, description = "sample")
public String duplicateParam2(@RequestParam String sample) {
return "duplicateParam";
}


@GetMapping("/duplicate_param3")
@Operation(summary = "Duplicate param")
@Parameter(name = "sample", required = true, description = "sample")
public String duplicateParam3(@RequestHeader String sample) {
return "duplicateParam";
}
}

0 comments on commit 7426a96

Please sign in to comment.