diff --git a/docs/generators/java-helidon-server.md b/docs/generators/java-helidon-server.md
index 031034d80a41..5cb19ee12b07 100644
--- a/docs/generators/java-helidon-server.md
+++ b/docs/generators/java-helidon-server.md
@@ -29,17 +29,12 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|bigDecimalAsString|Treat BigDecimal values as Strings to avoid precision loss.| |false|
|booleanGetterPrefix|Set booleanGetterPrefix| |get|
|dateLibrary|Option. Date library to use|
- **joda**
- Joda (for legacy app only)
- **legacy**
- Legacy java.util.Date
- **java8-localdatetime**
- Java 8 using LocalDateTime (for legacy app only)
- **java8**
- Java 8 native JSR310 (preferred for jdk 1.8+)
|java8|
-|developerEmail|developer email in generated pom.xml| |team@openapitools.org|
-|developerName|developer name in generated pom.xml| |OpenAPI-Generator Contributors|
-|developerOrganization|developer organization in generated pom.xml| |OpenAPITools.org|
-|developerOrganizationUrl|developer organization URL in generated pom.xml| |http://openapitools.org|
-|disableHtmlEscaping|Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)| |false|
|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|- **false**
- The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
- **true**
- Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.
|true|
|discriminatorCaseSensitive|Whether the discriminator value lookup should be case-sensitive or not. This option only works for Java API client| |true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|- **false**
- No changes to the enum's are made, this is the default option.
- **true**
- With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.
|false|
|fullJavaUtil|whether to use fully qualified name for classes under java.util. This option only works for Java API client| |false|
-|fullProject|Whether to generate full project with registered services and configured routing| |false|
+|fullProject|If set to true, it will generate all files; if set to false, it will only generate API files. If unspecified, the behavior depends on whether a project exists or not: if it does not, same as true; if it does, same as false. Note that test files are never overwritten.| ||
|groupId|groupId in generated pom.xml| |org.openapitools|
|helidonVersion|Helidon version for generated code| |2.5.2|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false|
@@ -53,14 +48,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|licenseUrl|The URL of the license| |http://unlicense.org|
|modelPackage|package for generated models| |org.openapitools.server.model|
|openApiNullable|Enable OpenAPI Jackson Nullable library| |true|
-|parentArtifactId|parent artifactId in generated pom N.B. parentGroupId, parentArtifactId and parentVersion must all be specified for any of them to take effect| |null|
-|parentGroupId|parent groupId in generated pom N.B. parentGroupId, parentArtifactId and parentVersion must all be specified for any of them to take effect| |null|
-|parentVersion|parent version in generated pom N.B. parentGroupId, parentArtifactId and parentVersion must all be specified for any of them to take effect| |null|
|performBeanValidation|Perform BeanValidation| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
-|scmConnection|SCM connection in generated pom.xml| |scm:git:git@github.com:openapitools/openapi-generator.git|
-|scmDeveloperConnection|SCM developer connection in generated pom.xml| |scm:git:git@github.com:openapitools/openapi-generator.git|
-|scmUrl|SCM URL in generated pom.xml| |https://github.com/openapitools/openapi-generator|
|serializableModel|boolean - toggle "implements Serializable" for generated models| |false|
|serializationLibrary|Serialization library, defaults to Jackson|- **jsonb**
- Use JSON-B as serialization library
- **jackson**
- Use Jackson as serialization library
|null|
|snapshotVersion|Uses a SNAPSHOT version.|- **true**
- Use a SnapShot Version
- **false**
- Use a Release Version
|null|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonServerCodegen.java
index 2d58ac11e193..4d0436bc2b90 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonServerCodegen.java
@@ -17,6 +17,9 @@
package org.openapitools.codegen.languages;
import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -47,14 +50,19 @@ public class JavaHelidonServerCodegen extends JavaHelidonCommonCodegen {
private final Logger LOGGER = LoggerFactory.getLogger(JavaHelidonServerCodegen.class);
+ //TODO remove it if MP does not support it
public static final String INTERFACE_ONLY = "interfaceOnly";
+ public static final String USE_ABSTRACT_CLASS = "useAbstractClass";
+ public static final String GRADLE_PROJECT = "gradleProject";
protected boolean useBeanValidation = true;
protected String implFolder = "src/main/java";
protected String serializationLibrary = null;
+ //TODO remove it if MP does not support it
private boolean interfaceOnly = false;
- private boolean fullProject = false;
+ private boolean useAbstractClass = false;
+ private boolean gradleProject = false;
public JavaHelidonServerCodegen() {
super();
@@ -71,7 +79,7 @@ public JavaHelidonServerCodegen() {
artifactId = "openapi-java-server";
apiPackage = invokerPackage + ".api";
modelPackage = invokerPackage + ".model";
- sourceFolder = "src" + File.separator + "main"+ File.separator + "java";
+ sourceFolder = "src" + File.separator + "main" + File.separator + "java";
// clioOptions default redefinition need to be updated
updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage());
@@ -85,6 +93,10 @@ public JavaHelidonServerCodegen() {
cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation"));
cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY,
"Whether to generate only API interface stubs without the server files.", interfaceOnly));
+ cliOptions.add(CliOption.newBoolean(USE_ABSTRACT_CLASS,
+ "Whether to generate abstract classes for REST API instead of interfaces.", useAbstractClass));
+ cliOptions.add(CliOption.newBoolean(GRADLE_PROJECT,
+ "Whether to generate gradle project instead of maven.", gradleProject));
// clear model and api doc template as this codegen
// does not support auto-generated markdown doc at the moment
@@ -126,15 +138,22 @@ public void processOpts() {
supportingFiles.clear();
dateLibrary = "java8";
- supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
- supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
- supportingFiles.add(new SupportingFile("openapi.mustache",
- ("src/main/resources/META-INF").replace("/", java.io.File.separator), "openapi.yml"));
- supportingFiles.add(new SupportingFile("logging.mustache",
- ("src.main.resources").replace(".", java.io.File.separator), "logging.properties"));
- supportingFiles.add(new SupportingFile("package-info.mustache",
- (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator),
- "package-info.java"));
+ SupportingFile pomFile = new SupportingFile("pom.mustache", "", "pom.xml");
+ SupportingFile readmeFile = new SupportingFile("README.mustache", "", "README.md");
+ SupportingFile openApiFile = new SupportingFile("openapi.mustache",
+ ("src/main/resources/META-INF").replace("/", File.separator), "openapi.yml");
+ SupportingFile logFile = new SupportingFile("logging.mustache",
+ ("src.main.resources").replace(".", File.separator), "logging.properties");
+ SupportingFile packageInfoFile = new SupportingFile("package-info.mustache",
+ (sourceFolder + File.separator + invokerPackage).replace(".", File.separator),
+ "package-info.java");
+ List modifiable = new ArrayList<>();
+ modifiable.add(pomFile);
+ modifiable.add(readmeFile);
+ modifiable.add(logFile);
+ modifiable.add(packageInfoFile);
+ List unmodifiable = new ArrayList<>();
+ unmodifiable.add(openApiFile);
if (additionalProperties.containsKey(USE_BEANVALIDATION)) {
this.setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION));
@@ -152,11 +171,18 @@ public void processOpts() {
additionalProperties.remove(INTERFACE_ONLY);
}
- if (additionalProperties.containsKey(FULL_PROJECT)) {
- fullProject = Boolean.parseBoolean(additionalProperties.get(FULL_PROJECT).toString());
+ if (additionalProperties.containsKey(USE_ABSTRACT_CLASS)) {
+ useAbstractClass = Boolean.parseBoolean(additionalProperties.get(USE_ABSTRACT_CLASS).toString());
}
- if (!fullProject) {
- additionalProperties.remove(FULL_PROJECT);
+ if (!useAbstractClass) {
+ additionalProperties.remove(USE_ABSTRACT_CLASS);
+ }
+
+ if (additionalProperties.containsKey(GRADLE_PROJECT)) {
+ gradleProject = Boolean.parseBoolean(additionalProperties.get(GRADLE_PROJECT).toString());
+ }
+ if (!gradleProject) {
+ additionalProperties.remove(GRADLE_PROJECT);
}
if (!additionalProperties.containsKey(MICROPROFILE_ROOT_PACKAGE)) {
@@ -177,22 +203,28 @@ public void processOpts() {
String resourceFolder = "src" + File.separator + "main" + File.separator + "resources";
String metaInfFolder = resourceFolder + File.separator + "META-INF";
supportingFiles.add(new SupportingFile("RestApplication.mustache", invokerFolder, "RestApplication.java"));
- supportingFiles.add(new SupportingFile("microprofile-config.properties.mustache", metaInfFolder, "microprofile-config.properties"));
+ supportingFiles.add(new SupportingFile("microprofile-config.properties.mustache", metaInfFolder, "microprofile" +
+ "-config.properties"));
supportingFiles.add(new SupportingFile("beans.xml.mustache", metaInfFolder, "beans.xml"));
+ processSupportingFiles(modifiable, unmodifiable);
} else if (isLibrary(HELIDON_SE)) {
artifactId = "openapi-helidon-se-server";
- if (!interfaceOnly) {
- supportingFiles.add(new SupportingFile("application.mustache",
- ("src.main.resources").replace(".", java.io.File.separator), "application.yaml"));
- supportingFiles.add(new SupportingFile("mainTest.mustache",
- (testFolder + File.separator + invokerPackage).replace(".", java.io.File.separator),
- "MainTest.java"));
- supportingFiles.add(new SupportingFile("main.mustache",
- (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator),
- "Main.java"));
- supportingFiles.add(new SupportingFile("validatorUtils.mustache",
- (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
- "ValidatorUtils.java"));
+
+ //TODO move this lines from this clause if MP will support it
+ addApiTemplateFiles();
+
+ modifiable.add(new SupportingFile("application.mustache",
+ ("src.main.resources").replace(".", java.io.File.separator), "application.yaml"));
+ modifiable.add(new SupportingFile("mainTest.mustache",
+ (testFolder + File.separator + invokerPackage).replace(".", java.io.File.separator),
+ "MainTest.java"));
+ modifiable.add(new SupportingFile("main.mustache",
+ (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator),
+ "Main.java"));
+ unmodifiable.add(new SupportingFile("validatorUtils.mustache",
+ (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
+ "ValidatorUtils.java"));
+ if (useAbstractClass) {
importMapping.put("Map", "java.util.Map");
importMapping.put("HashMap", "java.util.HashMap");
importMapping.put("InputStream", "java.io.InputStream");
@@ -205,9 +237,13 @@ public void processOpts() {
importMapping.put("ByteArrayInputStream", "java.io.ByteArrayInputStream");
}
importMapping.put("Handler", "io.helidon.webserver.Handler");
- //TODO after adding gradle support for Helidon MP move these 2 lines from this clause to the top of the method
- supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
- supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
+ //TODO after adding gradle support for Helidon MP move these lines from this clause to the top of the method
+ if (gradleProject) {
+ modifiable.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
+ modifiable.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
+ modifiable.remove(pomFile);
+ }
+ processSupportingFiles(modifiable, unmodifiable);
} else if (isLibrary(HELIDON_NIMA)) {
throw new UnsupportedOperationException("Not implemented");
} else if (isLibrary(HELIDON_NIMA_ANNOTATIONS)) {
@@ -249,24 +285,34 @@ public void processOpts() {
}
}
+ private void addApiTemplateFiles() {
+ Boolean fullProject = !additionalProperties.containsKey(FULL_PROJECT) ? null :
+ Boolean.parseBoolean(additionalProperties.get(FULL_PROJECT).toString());
+ if (fullProject == null && !projectFilesExist()) {
+ apiTemplateFiles.put("apiImpl.mustache", "Impl.java");
+ } else if (Boolean.TRUE.equals(fullProject)) {
+ apiTemplateFiles.put("apiImpl.mustache", "Impl.java");
+ }
+ }
+
@Override
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) {
CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers);
if (HELIDON_SE.equals(getLibrary())) {
- if (additionalProperties.containsKey(JACKSON)){
+ if (additionalProperties.containsKey(JACKSON)) {
codegenOperation.imports.add("ObjectMapper");
}
- if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JSONB)){
+ if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JSONB)) {
codegenOperation.imports.add("Jsonb");
codegenOperation.imports.add("JsonbBuilder");
}
if (codegenOperation.bodyParam != null) {
codegenOperation.imports.add("Handler");
}
- if (codegenOperation.queryParams.size() > 0 && !interfaceOnly) {
+ if (codegenOperation.queryParams.size() > 0 && useAbstractClass) {
codegenOperation.imports.add("List");
}
- if (codegenOperation.formParams.size() > 0 && !interfaceOnly) {
+ if (codegenOperation.formParams.size() > 0 && useAbstractClass) {
codegenOperation.imports.add("Map");
codegenOperation.imports.add("HashMap");
codegenOperation.imports.add("InputStream");
@@ -376,5 +422,19 @@ public void setSerializationLibrary(String serializationLibrary) {
throw new IllegalArgumentException("Unexpected serializationLibrary value: " + serializationLibrary);
}
}
+
+ /**
+ * Check if pom file and src directory already exist.
+ *
+ * @return outcome of test
+ */
+ @Override
+ protected boolean projectFilesExist() {
+ Path projectFolder = Paths.get(getOutputTestFolder());
+ Path pom = projectFolder.resolve("pom.xml");
+ Path buildGradle = projectFolder.resolve("build.gradle");
+ Path src = projectFolder.resolve(Paths.get(sourceFolder, invokerPackage.replace('.', File.separatorChar)));
+ return (pom.toFile().exists() || buildGradle.toFile().exists()) && src.toFile().exists();
+ }
}
diff --git a/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/api.mustache b/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/api.mustache
index b0a256b5032a..c44408d778bf 100644
--- a/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/api.mustache
+++ b/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/api.mustache
@@ -3,73 +3,65 @@ package {{package}};
{{#imports}}import {{import}};
{{/imports}}
-{{^interfaceOnly}}
+{{#useAbstractClass}}
import java.util.Optional;
import java.util.logging.Logger;
import io.helidon.common.GenericType;
import io.helidon.common.reactive.Single;
-import io.helidon.config.Config;
-{{/interfaceOnly}}
+{{/useAbstractClass}}
import io.helidon.webserver.Routing;
import io.helidon.webserver.ServerRequest;
import io.helidon.webserver.ServerResponse;
import io.helidon.webserver.Service;
{{#operations}}
-{{#interfaceOnly}}public interface {{classname}} extends Service { {{/interfaceOnly}}
-{{^interfaceOnly}}public {{^fullProject}}abstract {{/fullProject}}class {{classname}} implements Service { {{/interfaceOnly}}
-{{^interfaceOnly}}
+{{^useAbstractClass}}public interface {{classname}} extends Service { {{/useAbstractClass}}
+{{#useAbstractClass}}public abstract class {{classname}} implements Service {
protected static final Logger LOGGER = Logger.getLogger({{classname}}.class.getName());
{{#jackson}}
- private static final ObjectMapper MAPPER = JsonProvider.objectMapper();{{/jackson}}
+ protected static final ObjectMapper MAPPER = JsonProvider.objectMapper();{{/jackson}}
{{#jsonb}}
- private static final Jsonb JSONB = JsonbBuilder.create();{{/jsonb}}{{#fullProject}}
- private static final int HTTP_CODE_NOT_IMPLEMENTED = 501;{{/fullProject}}
- protected final Config config;
-
- public {{classname}}(Config config) {
- this.config = config;
- }
-{{/interfaceOnly}}
+ protected static final Jsonb JSONB = JsonbBuilder.create();{{/jsonb}}
+{{/useAbstractClass}}
/**
* A service registers itself by updating the routing rules.
* @param rules the routing rules.
*/
@Override
- {{^interfaceOnly}}public{{/interfaceOnly}}{{#interfaceOnly}}default{{/interfaceOnly}} void update(Routing.Rules rules) {
+ {{#useAbstractClass}}public{{/useAbstractClass}}{{^useAbstractClass}}default{{/useAbstractClass}} void update(Routing.Rules rules) {
{{#operation}}
rules.{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}("{{{path}}}", {{!
}}{{#bodyParam}}{{#isModel}}Handler.create({{{dataType}}}.class, {{/isModel}}this::{{{operationId}}}){{#isModel}}){{/isModel}}{{/bodyParam}}{{!
}}{{^bodyParam}}this::{{{operationId}}}){{/bodyParam}};
{{/operation}}
}
-{{^interfaceOnly}}{{#isFormParamsFunctions}}
+{{#useAbstractClass}}{{#isFormParamsFunctions}}
{{!}}{{>formParamsFunctions}}
-{{/isFormParamsFunctions}}{{/interfaceOnly}}
-
+{{/isFormParamsFunctions}}{{/useAbstractClass}}
{{#operation}}
+
/**
* {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}}.
* @param request the server request
* @param response the server response{{#allParams}}{{#isBodyParam}}{{#isModel}}
* @param {{paramName}} {{{description}}}{{^description}}{{paramName}}{{/description}} {{/isModel}}{{/isBodyParam}}{{/allParams}}
*/
- void {{{operationId}}}(ServerRequest request, ServerResponse response{{#allParams}}{{#isBodyParam}}{{#isModel}}, {{{dataType}}} {{paramName}}{{/isModel}}{{/isBodyParam}}{{/allParams}}){{#interfaceOnly}};{{/interfaceOnly}}{{^interfaceOnly}} { {{#formParams}}{{#-first}}
+ void {{{operationId}}}(ServerRequest request, ServerResponse response{{#allParams}}{{#isBodyParam}}{{#isModel}}, {{{dataType}}} {{paramName}}{{/isModel}}{{/isBodyParam}}{{/allParams}}){{^useAbstractClass}};{{/useAbstractClass}}{{#useAbstractClass}} { {{#formParams}}{{#-first}}
{{>formParamsInitial}}{{/-first}}{{/formParams}}
Single.create({{^hasParams}}Single.empty(){{/hasParams}}{{#hasParams}}{{^bodyParam}}{{#formParams}}{{#-first}}formSingle{{/-first}}{{/formParams}}{{^formParams}}Single.empty(){{/formParams}}{{/bodyParam}}{{#bodyParam}}{{^isModel}}request.content().as(new GenericType<{{{dataType}}}>() { }){{/isModel}}{{#isModel}}Single.empty(){{/isModel}}{{/bodyParam}}{{/hasParams}})
.thenAccept({{#bodyParam}}{{^isModel}}{{paramName}}{{/isModel}}{{#isModel}}val{{/isModel}}{{/bodyParam}}{{^bodyParam}}val{{/bodyParam}} -> {
- {{#allParams}}{{> queryParams }}{{> pathParams }}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}
- {{/allParams}}{{^fullProject}}
- handle{{#lambda.titlecase}}{{{operationId}}}{{/lambda.titlecase}}(request, response{{#allParams}}, {{paramName}}{{/allParams}});{{/fullProject}}{{#fullProject}}
- response.status(HTTP_CODE_NOT_IMPLEMENTED).send();{{/fullProject}}
+{{#allParams}}
+ {{> queryParams }}{{> pathParams }}{{> headerParams}}{{> bodyParams}}{{> formParams}}{{> cookieParams}}
+{{/allParams}}
+ handle{{#lambda.titlecase}}{{{operationId}}}{{/lambda.titlecase}}(request, response{{#allParams}}, {{paramName}}{{/allParams}});
})
- .exceptionally({{^fullProject}}throwable -> handleError(request, response, throwable){{/fullProject}}{{#fullProject}}response::send{{/fullProject}});
+ .exceptionally(throwable -> handleError(request, response, throwable));
}
-{{^fullProject}}
+
/**
* Handle {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}}.
* @param request the server request
@@ -77,10 +69,10 @@ import io.helidon.webserver.Service;
* @param {{paramName}} {{{description}}}{{^description}}{{paramName}}{{/description}} {{/allParams}}
*/
abstract void handle{{#lambda.titlecase}}{{{operationId}}}{{/lambda.titlecase}}(ServerRequest request, ServerResponse response{{#allParams}}, {{>dataType}} {{paramName}}{{/allParams}});
-{{/fullProject}}{{/interfaceOnly}}
+{{/useAbstractClass}}
{{/operation}}
-{{^interfaceOnly}}{{^fullProject}} abstract Void handleError(ServerRequest request, ServerResponse response, Throwable throwable);{{!
-}}{{/fullProject}}{{/interfaceOnly}}
+{{#useAbstractClass}} abstract Void handleError(ServerRequest request, ServerResponse response, Throwable throwable);{{!
+}}{{/useAbstractClass}}
}
{{/operations}}
diff --git a/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/apiImpl.mustache b/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/apiImpl.mustache
new file mode 100644
index 000000000000..b6cf71293f52
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/apiImpl.mustache
@@ -0,0 +1,40 @@
+package {{package}};
+
+{{#imports}}import {{import}};
+{{/imports}}
+{{^useAbstractClass}}
+import java.util.logging.Logger;{{/useAbstractClass}}
+
+import io.helidon.webserver.ServerRequest;
+import io.helidon.webserver.ServerResponse;
+
+{{#operations}}
+public class {{classname}}Impl {{^useAbstractClass}}implements{{/useAbstractClass}}{{#useAbstractClass}}extends{{/useAbstractClass}} {{classname}} {
+
+ private static final int HTTP_CODE_NOT_IMPLEMENTED = 501;
+{{^useAbstractClass}}
+ private static final Logger LOGGER = Logger.getLogger({{classname}}.class.getName());
+{{#jackson}}
+ private static final ObjectMapper MAPPER = JsonProvider.objectMapper();{{/jackson}}
+{{#jsonb}}
+ private static final Jsonb JSONB = JsonbBuilder.create();{{/jsonb}}
+{{/useAbstractClass}}
+{{#operation}}
+
+{{#useAbstractClass}}
+ public void handle{{#lambda.titlecase}}{{{operationId}}}{{/lambda.titlecase}}(ServerRequest request, ServerResponse response{{#allParams}}, {{>dataType}} {{paramName}}{{/allParams}}) {
+{{/useAbstractClass}}
+{{^useAbstractClass}}
+ public void {{{operationId}}}(ServerRequest request, ServerResponse response{{#allParams}}{{#isBodyParam}}{{#isModel}}, {{{dataType}}} {{paramName}}{{/isModel}}{{/isBodyParam}}{{/allParams}}) {
+{{/useAbstractClass}}
+ response.status(HTTP_CODE_NOT_IMPLEMENTED).send();
+ }
+{{/operation}}
+
+{{#useAbstractClass}}
+ public Void handleError(ServerRequest request, ServerResponse response, Throwable throwable) {
+ return response.send(throwable);
+ }
+{{/useAbstractClass}}
+}
+{{/operations}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/main.mustache b/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/main.mustache
index 840fdcb640e2..575d3704448a 100644
--- a/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/main.mustache
+++ b/modules/openapi-generator/src/main/resources/java-helidon/server/libraries/se/main.mustache
@@ -1,6 +1,6 @@
package {{invokerPackage}};
-{{#fullProject}}{{#apiInfo}}{{#apis}}{{#operations}}
-import {{package}}.{{classname}};{{/operations}}{{/apis}}{{/apiInfo}}{{/fullProject}}
+{{#apiInfo}}{{#apis}}{{#operations}}
+import {{package}}.{{classname}}Impl;{{/operations}}{{/apis}}{{/apiInfo}}
import io.helidon.common.LogConfig;
import io.helidon.common.reactive.Single;
@@ -94,8 +94,8 @@ public final class Main {
return Routing.builder()
.register(OpenAPISupport.create(config.get(OpenAPISupport.Builder.CONFIG_KEY)))
.register(health) // Health at "/health"
- .register(metrics) // Metrics at "/metrics"{{#fullProject}}{{#apiInfo}}{{#apis}}{{#operations}}
- .register("/", new {{classname}}(config)){{/operations}}{{/apis}}{{/apiInfo}}{{/fullProject}}
+ .register(metrics) // Metrics at "/metrics"{{#apiInfo}}{{#apis}}{{#operations}}
+ .register("/", new {{classname}}Impl()){{/operations}}{{/apis}}{{/apiInfo}}
.build();
}
}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonMpServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonMpServerCodegenTest.java
index 78abd63d4b01..ff577fbe74df 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonMpServerCodegenTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonMpServerCodegenTest.java
@@ -4,6 +4,7 @@
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import java.io.File;
@@ -43,6 +44,8 @@ private void generate() {
generate(createConfigurator());
}
+ //TODO remove it or change after MP implements new fullProject option
+ @Ignore
@Test
public void testAbstractClass() {
generate(createConfigurator().addAdditionalProperty("fullProject", "false"));
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonSeServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonSeServerCodegenTest.java
index 95a014b71670..fb629a114ede 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonSeServerCodegenTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/JavaHelidonSeServerCodegenTest.java
@@ -9,12 +9,15 @@
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.DefaultGenerator;
+import org.openapitools.codegen.Generator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import static org.testng.Assert.assertTrue;
+
public class JavaHelidonSeServerCodegenTest {
private DefaultGenerator generator;
@@ -26,70 +29,72 @@ public void setup() throws IOException {
output.deleteOnExit();
outputPath = output.getAbsolutePath().replace('\\', '/');
- final CodegenConfigurator configurator = new CodegenConfigurator()
- .setGeneratorName("java-helidon-server")
- .setLibrary("se")
- .setInputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml")
- .setOutputDir(outputPath);
+ final CodegenConfigurator configurator = codegenConfigurator(new HashMap<>());
final ClientOptInput clientOptInput = configurator.toClientOptInput();
generator = new DefaultGenerator();
generator.opts(clientOptInput);
}
- @Test
- public void doGenerateFullProject() {
- Map additionalProperties = new HashMap<>();
- additionalProperties.put("fullProject", true);
- final CodegenConfigurator configurator = new CodegenConfigurator()
+ private CodegenConfigurator codegenConfigurator(Map additionalProperties) {
+ return new CodegenConfigurator()
.setGeneratorName("java-helidon-server")
.setLibrary("se")
.setAdditionalProperties(additionalProperties)
.setInputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml")
.setOutputDir(outputPath);
- generator.opts(configurator.toClientOptInput()).generate();
+ }
- JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
+
+ @Test
+ public void testGenerateFullProject() {
+ generator.generate();
+
+ JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetServiceImpl.java"))
.fileContains(
- "public class PetService implements Service",
+ "public class PetServiceImpl",
"response.status(HTTP_CODE_NOT_IMPLEMENTED).send();"
);
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/Main.java"))
.fileContains(
- "import org.openapitools.server.api.PetService;",
- ".register(\"/\", new PetService(config))"
+ "import org.openapitools.server.api.PetServiceImpl;",
+ ".register(\"/\", new PetServiceImpl())"
);
- TestUtils.assertFileNotContains(
- Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"),
- " abstract Void handleError(ServerRequest request, ServerResponse response, Throwable throwable);");
}
@Test
- public void doGenerateInterfaceOnly() {
- Map additionalProperties = new HashMap<>();
- additionalProperties.put("interfaceOnly", true);
- final CodegenConfigurator configurator = new CodegenConfigurator()
- .setGeneratorName("java-helidon-server")
- .setLibrary("se")
- .setAdditionalProperties(additionalProperties)
- .setInputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml")
- .setOutputDir(outputPath);
- generator.opts(configurator.toClientOptInput()).generate();
+ public void testGenerateProjectByDefault() {
+ generator.generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.fileContains(
- "public interface PetService extends Service",
- "default void update(Routing.Rules rules)",
+ "public interface PetService extends Service {",
+ "default void update(Routing.Rules rules) {",
+ "void addPet(ServerRequest request, ServerResponse response, Pet pet);",
"void deletePet(ServerRequest request, ServerResponse response);"
);
- TestUtils.assertFileNotExists(Paths.get(outputPath + "/src/main/java/org/openapitools/server/Main.java"));
- TestUtils.assertFileNotContains(Paths.get(outputPath + "/pom.xml"), "org.openapitools.server" +
- ".Main");
+ TestUtils.assertFileNotExists(Paths.get(outputPath + "/build.gradle"));
+ TestUtils.assertFileNotExists(Paths.get(outputPath + "/settings.gradle"));
}
@Test
- public void doGeneratePathParams() throws IOException {
- generator.generate();
+ public void testGenerateGradleProject() {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("gradleProject", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
+
+ assertTrue(Paths.get(outputPath + "/build.gradle").toFile().exists());
+ assertTrue(Paths.get(outputPath + "/settings.gradle").toFile().exists());
+ TestUtils.assertFileNotExists(Paths.get(outputPath + "/pom.xml"));
+ }
+
+ @Test
+ public void testGeneratePathParams() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("deletePet", "ServerRequest", "ServerResponse")
@@ -108,8 +113,11 @@ public void doGeneratePathParams() throws IOException {
}
@Test
- public void doGenerateQueryParams() throws IOException {
- generator.generate();
+ public void testGenerateQueryParams() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.fileContains("import java.util.List;")
@@ -129,8 +137,11 @@ public void doGenerateQueryParams() throws IOException {
}
@Test
- public void doGenerateBodyParams() throws IOException {
- generator.generate();
+ public void testGenerateBodyParams() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("update")
@@ -177,8 +188,11 @@ public void doGenerateBodyParams() throws IOException {
}
@Test
- public void doGenerateHeaderParams() throws IOException {
- generator.generate();
+ public void testGenerateHeaderParams() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("deletePet", "ServerRequest", "ServerResponse")
@@ -190,8 +204,11 @@ public void doGenerateHeaderParams() throws IOException {
}
@Test
- public void doGenerateCookiesParams() throws IOException {
- generator.generate();
+ public void testGenerateCookiesParams() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("deletePet", "ServerRequest", "ServerResponse")
@@ -209,8 +226,11 @@ public void doGenerateCookiesParams() throws IOException {
}
@Test
- public void doGenerateFormParams() throws IOException {
- generator.generate();
+ public void testGenerateFormParams() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("addPets", "ServerRequest", "ServerResponse")
@@ -237,8 +257,11 @@ public void doGenerateFormParams() throws IOException {
}
@Test
- public void doGenerateParamsValidation() throws IOException {
- generator.generate();
+ public void testGenerateParamsValidation() throws IOException {
+ Map additionalProperties = new HashMap<>();
+ additionalProperties.put("useAbstractClass", true);
+ final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
+ generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("findPetsByStatus")
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalBase.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalBase.java
index b74f9efb9aa7..c985972f5020 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalBase.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalBase.java
@@ -59,6 +59,7 @@ abstract class FunctionalBase {
protected static final String INTERFACE_ONLY = "InterfaceOnly";
protected static final String FULL_PROJECT = "fullProject";
+ protected static final String USE_ABSTRACT_CLASS = "useAbstractClass";
private String library;
private String generatorName;
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonMPServerTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonMPServerTest.java
index edf450f0144e..0df8bea10d49 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonMPServerTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonMPServerTest.java
@@ -17,6 +17,7 @@
package org.openapitools.codegen.java.helidon.functional;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import java.nio.file.Files;
@@ -47,6 +48,8 @@ void buildProjectInterfaceOnly() {
buildAndVerify("target/openapi-java-server.jar");
}
+ //TODO remove it or change after MP implements new fullProject option
+ @Ignore
@Test
void buildProjectAbstractClasses() {
generate(createConfigurator().addAdditionalProperty(FULL_PROJECT, "false"));
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonSeServerTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonSeServerTest.java
index 634f59931991..3ef3bb45e95c 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonSeServerTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/helidon/functional/FunctionalHelidonSeServerTest.java
@@ -16,9 +16,16 @@
package org.openapitools.codegen.java.helidon.functional;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
public class FunctionalHelidonSeServerTest extends FunctionalBase {
@BeforeClass
@@ -34,16 +41,39 @@ void buildPetstoreWithDefaultOptions() {
}
@Test
- void buildPetstoreWithInterfaceOnly() {
+ void buildPetstoreWithAbstractClasses() {
inputSpec("src/test/resources/3_0/petstore.yaml");
- generate(createConfigurator().addAdditionalProperty(FunctionalBase.INTERFACE_ONLY, "true"));
+ generate(createConfigurator().addAdditionalProperty(FunctionalBase.USE_ABSTRACT_CLASS, "true"));
buildAndVerify("target/openapi-java-server.jar");
}
@Test
- void buildPetstoreWithFullProject() {
+ void verifyFullProject() {
inputSpec("src/test/resources/3_0/petstore.yaml");
- generate(createConfigurator().addAdditionalProperty("fullProject", "true"));
+
+ // Generate project for first time and record pom's timestamp
+ generate(createConfigurator());
buildAndVerify("target/openapi-java-server.jar");
+ Path pom1 = outputPath.resolve("pom.xml");
+ assertThat(Files.exists(pom1), is(true));
+ long lastModified = pom1.toFile().lastModified();
+
+ // Re-generate project over same directory with fullProject unspecified
+ generate(createConfigurator(outputPath));
+ Path pom2 = outputPath.resolve("pom.xml");
+ assertThat(Files.exists(pom2), is(true));
+ assertThat(pom2.toFile().lastModified(), is(lastModified)); // not overwritten
+
+ // Re-generate project over same directory with fullProject false
+ generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "false"));
+ Path pom3 = outputPath.resolve("pom.xml");
+ assertThat(Files.exists(pom3), is(true));
+ assertThat(pom3.toFile().lastModified(), is(lastModified)); // not overwritten
+
+ // Re-generate project over same directory with fullProject true
+ generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "true"));
+ Path pom4 = outputPath.resolve("pom.xml");
+ assertThat(Files.exists(pom4), is(true));
+ assertThat(pom4.toFile().lastModified(), is(not(lastModified))); // overwritten
}
}