Skip to content

Commit

Permalink
Fixes for generating openAPI clients:
Browse files Browse the repository at this point in the history
 - Add ability to disable generating `path` attribute in Client annotation
 - Changed basePathSeparator default value to `.` symbol
 - Add suffixes by class-name or clientId to client base path placeholders
  • Loading branch information
altro3 committed Mar 6, 2024
1 parent 575ea8c commit 47c3146
Show file tree
Hide file tree
Showing 19 changed files with 154 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def openapiGenerate = tasks.register("generateOpenApi", OpenApiGeneratorTask) {
lang = "java"
generatedAnnotation = true
clientId = "myClient"
clientPath = true
ksp = false
classpath.from(configurations.openapiGenerator)
openApiDefinition.convention(layout.projectDirectory.file("petstore.json"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def openapiGenerate = tasks.register("generateOpenApi", OpenApiGeneratorTask) {
lang = "kotlin"
generatedAnnotation = true
clientId = "myClient"
clientPath = true
ksp = false
classpath.from(configurations.openapiGenerator)
openApiDefinition.convention(layout.projectDirectory.file("petstore.json"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def openapiGenerate = tasks.register("generateOpenApi", OpenApiGeneratorTask) {
lang = "kotlin"
generatedAnnotation = true
clientId = "myClient"
clientPath = true
ksp = true
classpath.from(configurations.openapiGenerator)
openApiDefinition.convention(layout.projectDirectory.file("petstore.json"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public abstract class OpenApiGeneratorTask extends DefaultTask {
@Input
public abstract Property<Boolean> getKsp();

@Input
public abstract Property<Boolean> getClientPath();

@Input
public abstract Property<String> getClientId();

Expand Down Expand Up @@ -140,6 +143,7 @@ public void execute() throws IOException {
args.add(lang.toUpperCase());
args.add(Boolean.toString(generatedAnnotation));
args.add(Boolean.toString(getKsp().get()));
args.add(Boolean.toString(getClientPath().get()));
args.add(getNameMapping().get().toString());
args.add(getClientId().getOrElse(""));
args.add(getApiNamePrefix().getOrElse(""));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;

/**
* The generator for creating Micronaut clients.
Expand All @@ -33,6 +36,7 @@ public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen<Jav
public static final String OPT_CONFIGURE_AUTH = "configureAuth";
public static final String OPT_CONFIGURE_AUTH_FILTER_PATTERN = "configureAuthFilterPattern";
public static final String OPT_CONFIGURE_CLIENT_ID = "configureClientId";
public static final String OPT_CLIENT_PATH = "clientPath";
public static final String ADDITIONAL_CLIENT_TYPE_ANNOTATIONS = "additionalClientTypeAnnotations";
public static final String AUTHORIZATION_FILTER_PATTERN = "authorizationFilterPattern";
public static final String BASE_PATH_SEPARATOR = "basePathSeparator";
Expand All @@ -43,8 +47,9 @@ public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen<Jav
protected boolean configureAuthorization;
protected List<String> additionalClientTypeAnnotations;
protected String authorizationFilterPattern;
protected String basePathSeparator = "-";
protected String basePathSeparator = ".";
protected String clientId;
protected boolean clientPath;

JavaMicronautClientCodegen() {

Expand All @@ -60,12 +65,22 @@ public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen<Jav
cliOptions.add(CliOption.newString(AUTHORIZATION_FILTER_PATTERN, "Configure the authorization filter pattern for the client. Generally defined when generating clients from multiple specification files"));
cliOptions.add(CliOption.newString(BASE_PATH_SEPARATOR, "Configure the separator to use between the application name and base path when referencing the property").defaultValue(basePathSeparator));
cliOptions.add(CliOption.newString(CLIENT_ID, "Configure the service ID for the Client"));
cliOptions.add(CliOption.newBoolean(OPT_CLIENT_PATH, "Generate code with @Client annotation path attribute", clientPath));

typeMapping.put("file", "byte[]");
typeMapping.put("responseFile", "InputStream");
importMapping.put("InputStream", "java.io.InputStream");
}

@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);
OperationMap operations = objs.getOperations();
objs.put("apiNameKebab", Utils.camelToKebab(operations.getPathPrefix() + apiNameSuffix));

return objs;
}

@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
Expand Down Expand Up @@ -144,6 +159,11 @@ public void processOpts() {
writePropertyBack(CLIENT_ID, this.clientId);
}

if (additionalProperties.containsKey(OPT_CLIENT_PATH)) {
clientPath = convertPropertyToBoolean(OPT_CLIENT_PATH);
}
writePropertyBack(OPT_CLIENT_PATH, clientPath);

var basePathSeparator = additionalProperties.get(BASE_PATH_SEPARATOR);
if (basePathSeparator != null) {
this.basePathSeparator = basePathSeparator.toString();
Expand Down Expand Up @@ -186,6 +206,10 @@ public void setClientId(final String clientId) {
this.clientId = clientId;
}

public void setClientPath(boolean clientPath) {
this.clientPath = clientPath;
}

public void setBasePathSeparator(final String basePathSeparator) {
this.basePathSeparator = basePathSeparator;
}
Expand All @@ -205,6 +229,7 @@ static class DefaultClientOptionsBuilder implements JavaMicronautClientOptionsBu
private String authorizationFilterPattern;
private String basePathSeparator;
private String clientId;
private boolean clientPath;
private boolean useAuth;
private boolean lombok;
private boolean plural;
Expand Down Expand Up @@ -265,12 +290,19 @@ public JavaMicronautClientOptionsBuilder withGeneratedAnnotation(boolean generat
return this;
}

@Override
public JavaMicronautClientOptionsBuilder withClientPath(boolean clientPath) {
this.clientPath = clientPath;
return this;
}

ClientOptions build() {
return new ClientOptions(
additionalClientTypeAnnotations,
authorizationFilterPattern,
basePathSeparator,
clientId,
clientPath,
useAuth,
lombok,
plural,
Expand All @@ -285,6 +317,7 @@ record ClientOptions(
String authorizationFilterPattern,
String basePathSeparator,
String clientId,
boolean clientPath,
boolean useAuth,
boolean lombok,
boolean plural,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,13 @@ public interface JavaMicronautClientOptionsBuilder extends GeneratorOptionsBuild
* @return this builder
*/
JavaMicronautClientOptionsBuilder withGeneratedAnnotation(boolean generatedAnnotation);

/**
* If set to true, Api annotation {@literal @}Client will be with `path` attribute.
*
* @param clientPath do we need add path attribute to {@literal @}Client annotation
*
* @return this builder
*/
JavaMicronautClientOptionsBuilder withClientPath(boolean clientPath);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;

/**
* The generator for creating Micronaut clients.
Expand All @@ -33,6 +36,7 @@ public class KotlinMicronautClientCodegen extends AbstractMicronautKotlinCodegen
public static final String OPT_CONFIGURE_AUTH = "configureAuth";
public static final String OPT_CONFIGURE_AUTH_FILTER_PATTERN = "configureAuthFilterPattern";
public static final String OPT_CONFIGURE_CLIENT_ID = "configureClientId";
public static final String OPT_CLIENT_PATH = "clientPath";
public static final String ADDITIONAL_CLIENT_TYPE_ANNOTATIONS = "additionalClientTypeAnnotations";
public static final String AUTHORIZATION_FILTER_PATTERN = "authorizationFilterPattern";
public static final String BASE_PATH_SEPARATOR = "basePathSeparator";
Expand All @@ -43,8 +47,9 @@ public class KotlinMicronautClientCodegen extends AbstractMicronautKotlinCodegen
protected boolean configureAuthorization;
protected List<String> additionalClientTypeAnnotations;
protected String authorizationFilterPattern;
protected String basePathSeparator = "-";
protected String basePathSeparator = ".";
protected String clientId;
protected boolean clientPath;

KotlinMicronautClientCodegen() {

Expand All @@ -60,12 +65,22 @@ public class KotlinMicronautClientCodegen extends AbstractMicronautKotlinCodegen
cliOptions.add(CliOption.newString(AUTHORIZATION_FILTER_PATTERN, "Configure the authorization filter pattern for the client. Generally defined when generating clients from multiple specification files"));
cliOptions.add(CliOption.newString(BASE_PATH_SEPARATOR, "Configure the separator to use between the application name and base path when referencing the property").defaultValue(basePathSeparator));
cliOptions.add(CliOption.newString(CLIENT_ID, "Configure the service ID for the Client"));
cliOptions.add(CliOption.newBoolean(OPT_CLIENT_PATH, "Generate code with @Client annotation path attribute", clientPath));

typeMapping.put("file", "ByteArray");
typeMapping.put("responseFile", "InputStream");
importMapping.put("InputStream", "java.io.InputStream");
}

@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);
OperationMap operations = objs.getOperations();
objs.put("apiNameKebab", Utils.camelToKebab(operations.getPathPrefix() + apiNameSuffix));

return objs;
}

@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
Expand Down Expand Up @@ -144,6 +159,11 @@ public void processOpts() {
writePropertyBack(CLIENT_ID, this.clientId);
}

if (additionalProperties.containsKey(OPT_CLIENT_PATH)) {
clientPath = convertPropertyToBoolean(OPT_CLIENT_PATH);
}
writePropertyBack(OPT_CLIENT_PATH, clientPath);

var basePathSeparator = additionalProperties.get(BASE_PATH_SEPARATOR);
if (basePathSeparator != null) {
this.basePathSeparator = basePathSeparator.toString();
Expand Down Expand Up @@ -184,6 +204,10 @@ public void setClientId(final String clientId) {
this.clientId = clientId;
}

public void setClientPath(boolean clientPath) {
this.clientPath = clientPath;
}

public void setBasePathSeparator(final String basePathSeparator) {
this.basePathSeparator = basePathSeparator;
}
Expand All @@ -203,6 +227,7 @@ static class DefaultClientOptionsBuilder implements KotlinMicronautClientOptions
private String authorizationFilterPattern;
private String basePathSeparator;
private String clientId;
private boolean clientPath;
private boolean plural;
private boolean useAuth;
private boolean fluxForArrays;
Expand Down Expand Up @@ -263,12 +288,19 @@ public KotlinMicronautClientOptionsBuilder withKsp(boolean ksp) {
return this;
}

@Override
public KotlinMicronautClientOptionsBuilder withClientPath(boolean clientPath) {
this.clientPath = clientPath;
return this;
}

ClientOptions build() {
return new ClientOptions(
additionalClientTypeAnnotations,
authorizationFilterPattern,
basePathSeparator,
clientId,
clientPath,
useAuth,
plural,
fluxForArrays,
Expand All @@ -283,6 +315,7 @@ record ClientOptions(
String authorizationFilterPattern,
String basePathSeparator,
String clientId,
boolean clientPath,
boolean useAuth,
boolean plural,
boolean fluxForArrays,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,13 @@ public interface KotlinMicronautClientOptionsBuilder extends GeneratorOptionsBui
* @return this builder
*/
KotlinMicronautClientOptionsBuilder withKsp(boolean ksp);

/**
* If set to true, Api annotation {@literal @}Client will be with `path` attribute.
*
* @param clientPath do we need add path attribute to {@literal @}Client annotation
*
* @return this builder
*/
KotlinMicronautClientOptionsBuilder withClientPath(boolean clientPath);
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,12 @@ public void configureJavaClientOptions() {
if (javaClientOptions.basePathSeparator() != null) {
javaClientCodegen.setBasePathSeparator(javaClientOptions.basePathSeparator());
}
javaClientCodegen.setClientPath(javaClientOptions.clientPath());
javaClientCodegen.setGeneratedAnnotation(javaClientOptions.generatedAnnotation());
javaClientCodegen.setConfigureAuthorization(javaClientOptions.useAuth());
javaClientCodegen.setLombok(javaClientOptions.lombok());
javaClientCodegen.setPlural(javaClientOptions.plural());
javaClientCodegen.setFluxForArrays(javaClientOptions.fluxForArrays());
javaClientCodegen.setGeneratedAnnotation(javaClientOptions.generatedAnnotation());
javaClientCodegen.setLombok(javaClientOptions.lombok());
}
}

Expand Down Expand Up @@ -327,11 +328,12 @@ public void configureKotlinClientOptions() {
if (kotlinClientOptions.basePathSeparator() != null) {
kotlinClientCodegen.setBasePathSeparator(kotlinClientOptions.basePathSeparator());
}
kotlinClientCodegen.setClientPath(kotlinClientOptions.clientPath());
kotlinClientCodegen.setGeneratedAnnotation(kotlinClientOptions.generatedAnnotation());
kotlinClientCodegen.setKsp(kotlinClientOptions.ksp());
kotlinClientCodegen.setConfigureAuthorization(kotlinClientOptions.useAuth());
kotlinClientCodegen.setPlural(kotlinClientOptions.plural());
kotlinClientCodegen.setFluxForArrays(kotlinClientOptions.fluxForArrays());
kotlinClientCodegen.setKsp(kotlinClientOptions.ksp());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CodegenModel;
Expand All @@ -32,19 +33,21 @@ public final class Utils {

public static final String DEFAULT_BODY_PARAM_NAME = "requestBody";

private static final Pattern CAMEL_CASE_PATTERN = Pattern.compile("([A-Z])(?=[a-z])|(?<=[a-z0-9])([A-Z])");

private Utils() {
}

public static void processGenericAnnotations(CodegenParameter parameter, boolean useBeanValidation, boolean isGenerateHardNullable,
boolean isNullable, boolean isRequired, boolean isReadonly, boolean withNullablePostfix) {
boolean isNullable, boolean isRequired, boolean isReadonly, boolean withNullablePostfix) {
CodegenProperty items = parameter.isMap ? parameter.additionalProperties : parameter.items;
String datatypeWithEnum = parameter.datatypeWithEnum == null ? parameter.dataType : parameter.datatypeWithEnum;
processGenericAnnotations(parameter.dataType, datatypeWithEnum, parameter.isArray, parameter.isMap, parameter.containerTypeMapped,
items, parameter.vendorExtensions, useBeanValidation, isGenerateHardNullable, isNullable, isRequired, isReadonly, withNullablePostfix);
}

public static void processGenericAnnotations(CodegenProperty property, boolean useBeanValidation, boolean isGenerateHardNullable,
boolean isNullable, boolean isRequired, boolean isReadonly, boolean withNullablePostfix) {
boolean isNullable, boolean isRequired, boolean isReadonly, boolean withNullablePostfix) {
CodegenProperty items = property.isMap ? property.additionalProperties : property.items;
String datatypeWithEnum = property.datatypeWithEnum == null ? property.dataType : property.datatypeWithEnum;
processGenericAnnotations(property.dataType, datatypeWithEnum, property.isArray, property.isMap, property.containerTypeMapped,
Expand Down Expand Up @@ -237,4 +240,9 @@ public static void addStrValueToEnum(CodegenModel model) {
varMap.put("strValue", value);
}
}

public static String camelToKebab(String str) {
return CAMEL_CASE_PATTERN.matcher(str).replaceAll("-$1$2")
.toLowerCase();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
{{#generatedAnnotation}}
{{>common/generatedAnnotation}}
{{/generatedAnnotation}}
@Client({{#configureClientId}}id = "{{clientId}}", path = {{/configureClientId}}"${{openbrace}}{{{applicationName}}}{{basePathSeparator}}base-path{{closebrace}}")
@Client({{#configureClientId}}{{#clientPath}}id = {{/clientPath}}{{/configureClientId}}"{{#configureClientId}}{{clientId}}{{/configureClientId}}{{^configureClientId}}${{openbrace}}{{{applicationName}}}{{basePathSeparator}}{{apiNameKebab}}{{basePathSeparator}}base-path{{closebrace}}{{/configureClientId}}"{{#configureClientId}}{{#clientPath}}, path = "${{openbrace}}{{{applicationName}}}{{basePathSeparator}}{{#configureClientId}}{{{clientId}}}{{/configureClientId}}{{^configureClientId}}{{apiNameKebab}}{{basePathSeparator}}{{/configureClientId}}{{basePathSeparator}}base-path{{closebrace}}"{{/clientPath}}{{/configureClientId}})
public interface {{classname}} {
{{#operations}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement
{{#generatedAnnotation}}
{{>common/generatedAnnotation}}
{{/generatedAnnotation}}
@Client({{#configureClientId}}id = "{{clientId}}", path = {{/configureClientId}}"\${{openbrace}}{{{applicationName}}}{{basePathSeparator}}base-path{{closebrace}}")
@Client({{#configureClientId}}{{#clientPath}}id = {{/clientPath}}{{/configureClientId}}"{{#configureClientId}}{{clientId}}{{/configureClientId}}{{^configureClientId}}\${{openbrace}}{{{applicationName}}}{{basePathSeparator}}{{apiNameKebab}}{{basePathSeparator}}base-path{{closebrace}}{{/configureClientId}}"{{#configureClientId}}{{#clientPath}}, path = "\${{openbrace}}{{{applicationName}}}{{basePathSeparator}}{{#configureClientId}}{{{clientId}}}{{/configureClientId}}{{^configureClientId}}{{apiNameKebab}}{{basePathSeparator}}{{/configureClientId}}{{basePathSeparator}}base-path{{closebrace}}"{{/clientPath}}{{/configureClientId}})
interface {{classname}} {
{{#operations}}

Expand Down
Loading

0 comments on commit 47c3146

Please sign in to comment.