Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion modules/openapi-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,6 @@
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.24.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.java-diff-utils</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@

package org.openapitools.codegen.languages;

import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.Type;
import com.samskivert.mustache.Mustache;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
Expand Down Expand Up @@ -50,7 +57,6 @@
import java.net.URL;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.isNotEmpty;
Expand Down Expand Up @@ -1279,9 +1285,15 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
importMapping.put("Pageable", "org.springframework.data.domain.Pageable");
}

Set<String> provideArgsClassSet = reformatProvideArgsParams(operation);
ProvideArgsParams provideArgsParams = reformatProvideArgsParams(operation);

CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers);
if (!provideArgsParams.names.isEmpty()) {
codegenOperation.vendorExtensions.put("springProvideArgsNames", provideArgsParams.names);
}
if (!provideArgsParams.delegateArgs.isEmpty()) {
codegenOperation.vendorExtensions.put("springProvideArgsDelegate", provideArgsParams.delegateArgs);
}

// add org.springframework.format.annotation.DateTimeFormat when needed
codegenOperation.allParams.stream().filter(p -> p.isDate || p.isDateTime).findFirst()
Expand Down Expand Up @@ -1310,8 +1322,8 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
generatePageableConstraintValidation, useBeanValidation,
generateSortValidation, SpringPageableScanUtils.AnnotationSyntax.JAVA);
}
if (codegenOperation.vendorExtensions.containsKey("x-spring-provide-args") && !provideArgsClassSet.isEmpty()) {
codegenOperation.imports.addAll(provideArgsClassSet);
if (codegenOperation.vendorExtensions.containsKey("x-spring-provide-args") && !provideArgsParams.imports.isEmpty()) {
codegenOperation.imports.addAll(provideArgsParams.imports);
}

if (isSpringCodegen()) {
Expand Down Expand Up @@ -1395,41 +1407,82 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
return codegenOperation;
}

private Set<String> reformatProvideArgsParams(Operation operation) {
Set<String> provideArgsClassSet = new HashSet<>();
private ProvideArgsParams reformatProvideArgsParams(Operation operation) {
ProvideArgsParams provideArgsParams = new ProvideArgsParams();
Object argObj = operation.getExtensions().get("x-spring-provide-args");
if (argObj instanceof List) {
List<String> provideArgs = (List<String>) argObj;
if (!provideArgs.isEmpty()) {
List<String> formattedArgs = new ArrayList<>();
List<String> formattedArgNames = new ArrayList<>();
List<String> formattedDelegateArgs = new ArrayList<>();
for (String oneArg : provideArgs) {
if (StringUtils.isNotEmpty(oneArg)) {
String regexp = "(?<AnnotationTag>@)?(?<ClassPath>(?<PackageName>(\\w+\\.)*)(?<ClassName>\\w+))(?<Params>\\(.*?\\))?\\s?";
Matcher matcher = Pattern.compile(regexp).matcher(oneArg);
List<String> newArgs = new ArrayList<>();
while (matcher.find()) {
String className = matcher.group("ClassName");
String classPath = matcher.group("ClassPath");
String packageName = matcher.group("PackageName");
String params = matcher.group("Params");
String annoTag = matcher.group("AnnotationTag");
String shortPhrase = StringUtils.join(annoTag, className, params);
newArgs.add(shortPhrase);
if (StringUtils.isNotEmpty(packageName)) {
importMapping.put(className, classPath);
provideArgsClassSet.add(className);
LOGGER.trace("put import mapping {} {}", className, classPath);
}
}
String newArg = String.join(" ", newArgs);
Parameter parameter = parseProvideArgParameter(oneArg);
collectImportsAndSimplify(parameter, provideArgsParams);

String newArg = parameter.toString();
LOGGER.trace("new arg {} {}", newArg);
formattedArgs.add(newArg);

Parameter delegateParameter = parameter.clone();
delegateParameter.getAnnotations().clear();
formattedDelegateArgs.add(delegateParameter.toString());
formattedArgNames.add(parameter.getNameAsString());
}
}
operation.getExtensions().put("x-spring-provide-args", formattedArgs);
provideArgsParams.names.addAll(formattedArgNames);
provideArgsParams.delegateArgs.addAll(formattedDelegateArgs);
}
}
return provideArgsParams;
}

private Parameter parseProvideArgParameter(String oneArg) {
CompilationUnit compilationUnit = StaticJavaParser.parse(String.format(Locale.ROOT, "class Dummy { void method(%s) {} }", oneArg));
return compilationUnit.findFirst(MethodDeclaration.class)
.orElseThrow(() -> new IllegalArgumentException("Unable to parse x-spring-provide-args parameter: " + oneArg))
.getParameter(0);
}

private void collectImportsAndSimplify(Parameter parameter, ProvideArgsParams provideArgsParams) {
parameter.findAll(AnnotationExpr.class).forEach(annotation -> {
String annotationName = annotation.getNameAsString();
if (annotationName.contains(".")) {
String simpleName = annotation.getName().getIdentifier();
importMapping.put(simpleName, annotationName);
provideArgsParams.imports.add(simpleName);
annotation.setName(simpleName);
LOGGER.trace("put import mapping {} {}", simpleName, annotationName);
}
});

parameter.getType().toClassOrInterfaceType().ifPresent(type -> simplifyClassOrInterfaceType(type, provideArgsParams));
}

private void simplifyClassOrInterfaceType(ClassOrInterfaceType type, ProvideArgsParams provideArgsParams) {
type.getTypeArguments().stream()
.flatMap(Collection::stream)
.map(Type::toClassOrInterfaceType)
.flatMap(Optional::stream)
.forEach(classOrInterfaceType -> simplifyClassOrInterfaceType(classOrInterfaceType, provideArgsParams));
if (type.getScope().isPresent()) {
String typeName = type.getNameWithScope();
if (typeName.contains(".")) {
String simpleName = type.getNameAsString();
importMapping.put(simpleName, typeName);
provideArgsParams.imports.add(simpleName);
type.setScope(null);
LOGGER.trace("put import mapping {} {}", simpleName, typeName);
}
}
return provideArgsClassSet;
}

private static final class ProvideArgsParams {
private final Set<String> imports = new HashSet<>();
private final List<String> names = new ArrayList<>();
private final List<String> delegateArgs = new ArrayList<>();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,22 +279,22 @@ public interface {{classname}} {
{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},
{{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}},
{{/hasParams}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true){{/swagger2AnnotationLibrary}} final {{#reactive}}ServerWebExchange exchange{{/reactive}}{{^reactive}}HttpServletRequest servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}},
{{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}},{{/includeHttpRequestContext}}{{/hasParams}}{{#vendorExtensions.x-pageable-extra-annotation}}{{{.}}} {{/vendorExtensions.x-pageable-extra-annotation}}{{#springDocDocumentationProvider}}@ParameterObject{{/springDocDocumentationProvider}} final Pageable pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.x-spring-provide-args}}{{#hasParams}},
{{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}},{{/includeHttpRequestContext}}{{/hasParams}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true){{/swagger2AnnotationLibrary}} {{{.}}}{{^hasParams}}{{^-last}}{{^reactive}},{{/reactive}}
{{/-last}}{{/hasParams}}{{/vendorExtensions.x-spring-provide-args}}
{{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}},{{/includeHttpRequestContext}}{{/hasParams}}{{#vendorExtensions.x-pageable-extra-annotation}}{{{.}}} {{/vendorExtensions.x-pageable-extra-annotation}}{{#springDocDocumentationProvider}}@ParameterObject{{/springDocDocumentationProvider}} final Pageable pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.x-spring-provide-args}}{{#-first}}{{#hasParams}},
{{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}},{{/includeHttpRequestContext}}{{^includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}},{{/vendorExtensions.x-spring-paginated}}{{/includeHttpRequestContext}}{{/hasParams}}{{/-first}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true){{/swagger2AnnotationLibrary}} {{{.}}}{{^-last}},
{{/-last}}{{/vendorExtensions.x-spring-provide-args}}
){{#unhandledException}} throws Exception{{/unhandledException}}{{^jdk8-default-interface}};{{/jdk8-default-interface}}{{#jdk8-default-interface}} {
{{#delegate-method}}
{{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}});
{{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.springProvideArgsNames}}{{#-first}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{^includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}, {{/vendorExtensions.x-spring-paginated}}{{/includeHttpRequestContext}}{{/hasParams}}{{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{/vendorExtensions.springProvideArgsNames}});
}

// Override this method
{{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}MultipartFile{{#isArray}}>{{/isArray}}{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}} final {{#reactive}}ServerWebExchange exchange{{/reactive}}{{^reactive}}HttpServletRequest servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} {
{{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}MultipartFile{{#isArray}}>{{/isArray}}{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}} final {{#reactive}}ServerWebExchange exchange{{/reactive}}{{^reactive}}HttpServletRequest servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{/hasParams}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.springProvideArgsDelegate}}{{#-first}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{^includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}, {{/vendorExtensions.x-spring-paginated}}{{/includeHttpRequestContext}}{{/hasParams}}{{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{/vendorExtensions.springProvideArgsDelegate}}){{#unhandledException}} throws Exception{{/unhandledException}} {
{{/delegate-method}}
{{^isDelegate}}
{{>methodBody}}{{! prevent indent}}
{{/isDelegate}}
{{#isDelegate}}
{{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}getDelegate().{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}});
{{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}getDelegate().{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#includeHttpRequestContext}}{{#hasParams}}, {{/hasParams}}{{#reactive}}exchange{{/reactive}}{{^reactive}}servletRequest{{/reactive}}{{/includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.springProvideArgsNames}}{{#-first}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#includeHttpRequestContext}}, {{/includeHttpRequestContext}}{{^includeHttpRequestContext}}{{#vendorExtensions.x-spring-paginated}}, {{/vendorExtensions.x-spring-paginated}}{{/includeHttpRequestContext}}{{/hasParams}}{{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{/vendorExtensions.springProvideArgsNames}});
{{/isDelegate}}
}{{/jdk8-default-interface}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ public class {{classname}}Controller implements {{classname}} {
public {{#responseWrapper}}{{.}}<{{/responseWrapper}}{{#useResponseEntity}}ResponseEntity<{{/useResponseEntity}}{{>returnTypes}}{{#useResponseEntity}}>{{/useResponseEntity}}{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}(
{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},
{{/-last}}{{/allParams}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}},
{{/hasParams}}{{^hasParams}}{{#reactive}},{{/reactive}}{{/hasParams}}{{#springDocDocumentationProvider}}@ParameterObject {{/springDocDocumentationProvider}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}
{{/hasParams}}{{#springDocDocumentationProvider}}@ParameterObject {{/springDocDocumentationProvider}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.x-spring-provide-args}}{{#-first}}{{#hasParams}},
{{/hasParams}}{{^hasParams}}{{#vendorExtensions.x-spring-paginated}},
{{/vendorExtensions.x-spring-paginated}}{{/hasParams}}{{/-first}}{{#swagger2AnnotationLibrary}}@Parameter(hidden = true){{/swagger2AnnotationLibrary}} {{{.}}}{{^-last}},
{{/-last}}{{/vendorExtensions.x-spring-provide-args}}
) {
{{^isDelegate}}
{{^async}}
Expand All @@ -139,7 +142,7 @@ public class {{classname}}Controller implements {{classname}} {
{{/async}}
{{/isDelegate}}
{{#isDelegate}}
{{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}delegate.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}});
{{^isVoid}}return {{/isVoid}}{{#isVoid}}{{#useResponseEntity}}return {{/useResponseEntity}}{{^useResponseEntity}}{{#reactive}}return {{/reactive}}{{/useResponseEntity}}{{/isVoid}}delegate.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}pageable{{/vendorExtensions.x-spring-paginated}}{{#vendorExtensions.springProvideArgsNames}}{{#-first}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#vendorExtensions.x-spring-paginated}}, {{/vendorExtensions.x-spring-paginated}}{{/hasParams}}{{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{/vendorExtensions.springProvideArgsNames}});
{{/isDelegate}}
}

Expand Down
Loading