Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[quarkus2] Add new property "config-key" and use configKey instead openApiSpecId on templating #469

Merged
merged 2 commits into from
Sep 8, 2023
Merged
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
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,52 @@ It's also possible to only use a type mapping with a fully qualified name, for i

See the module [type-mapping](integration-tests/type-mapping) for an example of how to use this feature.

## Config key

By default, the `@RegisterRestClient` `configKey` property is the sanitized name of the file containing the OpenAPI spec. For example, if the file name is `petstore.json`, the `configKey` will be `petstore_json`:

```java
/* omitted */
@RegisterRestClient(configKey="petstore_json")
public interface DefaultApi { /* omitted */ }
}
```

If you want to use a different configKey than the default one, you can set the `quarkus.openapi-generator.codegen.spec.petstore_json.[config-key]` property.

Using the `config-key` the extension allow you to define all allowed properties with `quarkus.openapi-generator.codegen.spec.[my_custom_config_key].*` prefix. For example:

```properties
quarkus.openapi-generator.codegen.spec.petstore_json.config-key=petstore
quarkus.openapi-generator.codegen.spec.petstore.additional-api-type-annotations=@org.test.Foo
```

With it, you will have the following result:

```java
/* omitted */
@RegisterRestClient(configKey="petstore")
@org.test.Foo
public interface DefaultApi { /* omitted */ }
```

> **️⚠️ NOTE:** If you configure the property config-key, it will override the sanitized file name (will not consider the order of the configurations). For example, having the following configuration:

```properties
quarkus.openapi-generator.codegen.spec.petstore_json.config-key=custom_config_key
quarkus.openapi-generator.codegen.spec.custom_config_key.additional-api-type-annotations=@org.test.Foo
quarkus.openapi-generator.codegen.spec.petstore_json.additional-api-type-annotations=@org.test.Bar
```

The generated code will be:

```java
/* omitted */
@RegisterRestClient(configKey="custom_config_key")
@org.test.Foo
public interface DefaultApi { /* omitted */ }
```

## Template Customization

You have the option to swap out the [templates used by this extension](deployment/src/main/resources/templates/libraries/microprofile) with your customized versions. To achieve this, place your custom templates under the `resources/templates` directory. It's crucial that the filename of each custom template matches that of the original template.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public enum ConfigName {
NORMALIZER("open-api-normalizer"),
RETURN_RESPONSE("return-response"),
ENABLE_SECURITY_GENERATION("enable-security-generation"),
CONFIG_KEY("config-key"),
GENERATE_PART_FILENAME("generate-part-filename"),
PART_FILENAME_VALUE("part-filename-value"),
USE_FIELD_NAME_IN_PART_FILENAME("use-field-name-in-part-filename");
Expand Down Expand Up @@ -89,6 +90,17 @@ public static String getSpecConfigName(ConfigName configName, final Path openApi
return String.format("%s.%s", getBuildTimeSpecPropertyPrefix(openApiFilePath), configName.name);
}

/**
* Return spec config name by config-key (<b>openapi-generator.codegen.spec.%s.config-key</b>) property.
* For example, given a configuration <code>quarkus.openapi.generator.codegen.spec.spec_yaml.config-key=petstore</code>, the
* returned value is
* <code>openapi.generator.codegen.spec.petstore.mutiny</code>.
*/
public static String getSpecConfigNameByConfigKey(final String configKey, final ConfigName configName) {
String buildTimeSpecPropertyPrefix = String.format(BUILD_TIME_SPEC_PREFIX_FORMAT, configKey);
return String.format("%s.%s", buildTimeSpecPropertyPrefix, configName.name);
}

/**
* Gets the config prefix for a given OpenAPI file in the path.
* For example, given a path like /home/luke/projects/petstore.json, the returned value is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -48,6 +49,7 @@ public abstract class OpenApiGeneratorCodeGenBase implements CodeGenProvider {
static final String JSON = ".json";

private static final String DEFAULT_PACKAGE = "org.openapi.quarkus";
private static final String CONFIG_KEY_PROPERTY = "config-key";

/**
* The input base directory from
Expand Down Expand Up @@ -180,6 +182,10 @@ protected void generate(final Config config, final Path openApiFilePath, final P
getValues(config, openApiFilePath, CodegenConfig.ConfigName.ADDITIONAL_API_TYPE_ANNOTATIONS, String.class)
.ifPresent(generator::withAdditionalApiTypeAnnotationsConfig);

getConfigKeyValue(config, openApiFilePath)
.ifPresentOrElse(generator::withConfigKey,
() -> generator.withConfigKey(getSanitizedFileName(openApiFilePath)));

generator.withReturnResponse(
getValues(config, openApiFilePath, CodegenConfig.ConfigName.RETURN_RESPONSE, Boolean.class).orElse(false));

Expand Down Expand Up @@ -245,16 +251,78 @@ private Optional<String> getInputBaseDirRelativeToModule(final Path sourceDir, f

private <T> Optional<T> getValues(final Config config, final Path openApiFilePath, CodegenConfig.ConfigName configName,
Class<T> propertyType) {
return config
.getOptionalValue(CodegenConfig.getSpecConfigName(configName, openApiFilePath), propertyType)
.or(() -> config.getOptionalValue(CodegenConfig.getGlobalConfigName(configName), propertyType));

return getConfigKeyValues(config, openApiFilePath, configName, propertyType)
.or(() -> getValuesBySpecConfigName(config, openApiFilePath, configName, propertyType));
}

private <K, V> Optional<Map<K, V>> getValues(final SmallRyeConfig config, final Path openApiFilePath,
CodegenConfig.ConfigName configName,
Class<K> kClass, Class<V> vClass) {

return getConfigKeyValues(config, openApiFilePath, configName, kClass, vClass)
.or(() -> getValuesBySpecConfigName(config, openApiFilePath, configName, kClass, vClass));
}

private static <T> Optional<T> getValuesBySpecConfigName(Config config, Path openApiFilePath,
CodegenConfig.ConfigName configName,
Class<T> propertyType) {
return config
.getOptionalValue(CodegenConfig.getSpecConfigName(configName, openApiFilePath), propertyType)
.or(() -> config.getOptionalValue(CodegenConfig.getGlobalConfigName(configName), propertyType));
}

private static <K, V> Optional<Map<K, V>> getValuesBySpecConfigName(SmallRyeConfig config, Path openApiFilePath,
CodegenConfig.ConfigName configName, Class<K> kClass, Class<V> vClass) {
return config
.getOptionalValues(CodegenConfig.getSpecConfigName(configName, openApiFilePath), kClass, vClass)
.or(() -> config.getOptionalValues(CodegenConfig.getGlobalConfigName(configName), kClass, vClass));
}

private static <T> Optional<T> getValuesByConfigKey(Config config, String configName, Class<T> propertyType,
CodegenConfig.ConfigName codegenConfigName) {
return config
.getOptionalValue(configName, propertyType)
.or(() -> config.getOptionalValue(CodegenConfig.getGlobalConfigName(codegenConfigName), propertyType));
}

private static <K, V> Optional<Map<K, V>> getValuesByConfigKey(SmallRyeConfig config, CodegenConfig.ConfigName configName,
Class<K> kClass, Class<V> vClass, String configKey) {
return config
.getOptionalValues(CodegenConfig.getSpecConfigNameByConfigKey(configKey, configName), kClass,
vClass)
.or(() -> config.getOptionalValues(CodegenConfig.getGlobalConfigName(configName), kClass, vClass));
}

private static Optional<String> getConfigKeyValue(Config config, Path openApiFilePath) {
String configKey = String.format("quarkus.openapi-generator.codegen.spec.%s.%s", getSanitizedFileName(openApiFilePath),
CONFIG_KEY_PROPERTY);
return config.getOptionalValue(configKey, String.class)
.filter(Predicate.not(String::isBlank));
}

private <T> Optional<T> getConfigKeyValues(final Config config, final Path openApiFilePath,
CodegenConfig.ConfigName configName,
Class<T> propertyType) {

Optional<String> possibleConfigKey = getConfigKeyValue(config, openApiFilePath);
if (possibleConfigKey.isPresent()) {
return getValuesByConfigKey(config, CodegenConfig.getSpecConfigNameByConfigKey(possibleConfigKey.get(), configName),
propertyType, configName);
}

return Optional.empty();
}

private <K, V> Optional<Map<K, V>> getConfigKeyValues(final SmallRyeConfig config, final Path openApiFilePath,
CodegenConfig.ConfigName configName,
Class<K> kClass, Class<V> vClass) {

Optional<String> possibleConfigKey = getConfigKeyValue(config, openApiFilePath);
if (possibleConfigKey.isPresent()) {
return getValuesByConfigKey(config, configName, kClass, vClass, possibleConfigKey.get());
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.config.GlobalSettings;

import io.smallrye.config.common.utils.StringUtil;

/**
* Wrapper for the OpenAPIGen tool.
* This is the same as calling the Maven plugin or the CLI.
Expand Down Expand Up @@ -216,4 +218,10 @@ private void consolidatePackageNames() {
this.configurator.setModelPackage(modelPackage);
this.configurator.setInvokerPackage(apiPackage);
}

public void withConfigKey(final String config) {
if (config != null && !config.isBlank()) {
this.configurator.addAdditionalProperty("configKey", StringUtil.replaceNonAlphanumericByUnderscores(config));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import io.quarkiverse.openapi.generator.annotations.GeneratedParam;
*/
{/if}
@Path("{#if useAnnotatedBasePath}{contextPath}{/if}{commonPath}")
@RegisterRestClient({#if defaultServerUrl}baseUri="{defaultServerUrl}",{/if} configKey="{quarkus-generator.openApiSpecId}")
@RegisterRestClient({#if defaultServerUrl}baseUri="{defaultServerUrl}",{/if} configKey="{configKey}")
@GeneratedClass(value="{openapi:parseUri(inputSpec)}", tag = "{baseName}")
{#if enable-security-generation && hasAuthMethods}
@RegisterProvider(CompositeAuthenticationProvider.class)
Expand Down
89 changes: 89 additions & 0 deletions integration-tests/config-key/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-openapi-generator-integration-tests</artifactId>
<groupId>io.quarkiverse.openapi.generator</groupId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-openapi-generator-it-config-key</artifactId>
<name>Quarkus - Openapi Generator - Integration Tests - Config Key</name>

<dependencies>
<dependency>
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native-image</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${native.surefire.skip}</skipTests>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.quarkiverse.openapi.generator.configkey;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface AnotherCustomAnnotation {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.quarkiverse.openapi.generator.configkey;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
}
Loading