Add Helidon MP server code generator class and resources

Signed-off-by: tvallin <thibault.vallin@oracle.com>
This commit is contained in:
tvallin
2022-09-23 17:11:15 -05:00
committed by tim.quinn@oracle.com
parent cea7a14b25
commit 224f42e291
50 changed files with 1681 additions and 0 deletions
@@ -0,0 +1,419 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
import java.util.Map;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.servers.Server;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.openapitools.codegen.utils.StringUtils.camelize;
public class JavaHelidonServerCodegen extends JavaHelidonCommonCodegen {
private final Logger LOGGER = LoggerFactory.getLogger(JavaHelidonServerCodegen.class);
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;
private boolean useAbstractClass = false;
private boolean gradleProject = false;
public JavaHelidonServerCodegen() {
super();
// beta for now
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.BETA)
.build();
modifyFeatureSet(features -> features.includeDocumentationFeatures(DocumentationFeature.Readme));
outputFolder = "generated-code" + File.separator + "java";
embeddedTemplateDir = templateDir = "java-helidon" + File.separator + "server";
invokerPackage = "org.openapitools.server";
artifactId = "openapi-java-server";
apiPackage = invokerPackage + ".api";
modelPackage = invokerPackage + ".model";
sourceFolder = "src" + File.separator + "main" + File.separator + "java";
// clioOptions default redefinition need to be updated
updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage());
updateOption(CodegenConstants.ARTIFACT_ID, this.getArtifactId());
updateOption(CodegenConstants.API_PACKAGE, apiPackage);
updateOption(CodegenConstants.MODEL_PACKAGE, modelPackage);
modelTestTemplateFiles.put("model_test.mustache", ".java");
cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use Bean Validation"));
cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation"));
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
modelDocTemplateFiles.remove("model_doc.mustache");
apiDocTemplateFiles.remove("api_doc.mustache");
// clear test templates
// as this codegen does not support api tests at the moment
apiTestTemplateFiles.clear();
supportedLibraries.put(HELIDON_MP, "Helidon MP Server");
supportedLibraries.put(HELIDON_SE, "Helidon SE Server");
supportedLibraries.put(HELIDON_NIMA, "Helidon NIMA Server");
supportedLibraries.put(HELIDON_NIMA_ANNOTATIONS, "Helidon NIMA Annotations Server");
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use");
libraryOption.setEnum(supportedLibraries);
libraryOption.setDefault(HELIDON_SE);
cliOptions.add(libraryOption);
setLibrary(HELIDON_SE);
CliOption serializationLibrary = new CliOption(CodegenConstants.SERIALIZATION_LIBRARY,
"Serialization library, defaults to Jackson");
Map<String, String> serializationOptions = new HashMap<>();
serializationOptions.put(SERIALIZATION_LIBRARY_JACKSON, "Use Jackson as serialization library");
serializationOptions.put(SERIALIZATION_LIBRARY_JSONB, "Use JSON-B as serialization library");
serializationLibrary.setEnum(serializationOptions);
cliOptions.add(serializationLibrary);
setSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
removeUnusedOptions();
this.setLegacyDiscriminatorBehavior(false);
}
@Override
public void processOpts() {
super.processOpts();
supportingFiles.clear();
dateLibrary = "java8";
addApiTemplateFiles();
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<SupportingFile> modifiable = new ArrayList<>();
modifiable.add(pomFile);
modifiable.add(readmeFile);
modifiable.add(logFile);
modifiable.add(packageInfoFile);
List<SupportingFile> unmodifiable = new ArrayList<>();
unmodifiable.add(openApiFile);
if (additionalProperties.containsKey(USE_BEANVALIDATION)) {
this.setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION));
}
writePropertyBack(USE_BEANVALIDATION, useBeanValidation);
importMapping.put("ObjectMapper", "com.fasterxml.jackson.databind.ObjectMapper");
importMapping.put("Jsonb", rootJavaEEPackage() + ".json.bind.Jsonb");
importMapping.put("JsonbBuilder", rootJavaEEPackage() + ".json.bind.JsonbBuilder");
if (additionalProperties.containsKey(USE_ABSTRACT_CLASS)) {
useAbstractClass = Boolean.parseBoolean(additionalProperties.get(USE_ABSTRACT_CLASS).toString());
}
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);
} else {
modifiable.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
modifiable.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
modifiable.remove(pomFile);
}
if (additionalProperties.containsKey(CodegenConstants.SERIALIZATION_LIBRARY)) {
setSerializationLibrary(additionalProperties.get(CodegenConstants.SERIALIZATION_LIBRARY).toString());
}
String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");
if (additionalProperties.containsKey("jsr310") && isLibrary(HELIDON_MP)) {
supportingFiles.add(new SupportingFile("JavaTimeFormatter.mustache", invokerFolder, "JavaTimeFormatter.java"));
}
if (isLibrary(HELIDON_MP)) {
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("beans.xml.mustache", metaInfFolder, "beans.xml"));
processSupportingFiles(modifiable, unmodifiable);
} else if (isLibrary(HELIDON_SE)) {
artifactId = "openapi-helidon-se-server";
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");
importMapping.put("ReadableBodyPart", "io.helidon.media.multipart.ReadableBodyPart");
importMapping.put("ArrayList", "java.util.ArrayList");
importMapping.put("ByteArrayOutputStream", "java.io.ByteArrayOutputStream");
importMapping.put("DataChunk", "io.helidon.common.http.DataChunk");
importMapping.put("UncheckedIOException", "java.io.UncheckedIOException");
importMapping.put("IOException", "java.io.IOException");
importMapping.put("ByteArrayInputStream", "java.io.ByteArrayInputStream");
}
importMapping.put("Handler", "io.helidon.webserver.Handler");
processSupportingFiles(modifiable, unmodifiable);
} else if (isLibrary(HELIDON_NIMA)) {
throw new UnsupportedOperationException("Not implemented");
} else if (isLibrary(HELIDON_NIMA_ANNOTATIONS)) {
throw new UnsupportedOperationException("Not implemented");
} else {
LOGGER.error("Unknown library option (-l/--library): {}", getLibrary());
throw new IllegalArgumentException(
String.format(Locale.ROOT,
"Unknown library option %s for Helidon Server",
getLibrary()
)
);
}
if (getSerializationLibrary() == null) {
LOGGER.info("No serializationLibrary configured, using '{}' as fallback", SERIALIZATION_LIBRARY_JACKSON);
setSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
}
switch (getSerializationLibrary()) {
case SERIALIZATION_LIBRARY_JACKSON:
additionalProperties.put(SERIALIZATION_LIBRARY_JACKSON, "true");
additionalProperties.remove(SERIALIZATION_LIBRARY_JSONB);
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", invokerFolder, "RFC3339DateFormat.java"));
if (isLibrary(HELIDON_SE)) {
supportingFiles.add(new SupportingFile("jsonProvider.mustache",
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator),
"JsonProvider.java"));
}
break;
case SERIALIZATION_LIBRARY_JSONB:
additionalProperties.put(SERIALIZATION_LIBRARY_JSONB, "true");
additionalProperties.remove(SERIALIZATION_LIBRARY_JACKSON);
break;
default:
additionalProperties.remove(SERIALIZATION_LIBRARY_JACKSON);
additionalProperties.remove(SERIALIZATION_LIBRARY_JSONB);
LOGGER.error("Unknown serialization library option");
break;
}
}
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<Server> servers) {
CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, servers);
if (HELIDON_SE.equals(getLibrary())) {
if (additionalProperties.containsKey(JACKSON)) {
codegenOperation.imports.add("ObjectMapper");
}
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 && useAbstractClass) {
codegenOperation.imports.add("List");
}
if (codegenOperation.formParams.size() > 0 && useAbstractClass) {
codegenOperation.imports.add("Map");
codegenOperation.imports.add("HashMap");
codegenOperation.imports.add("InputStream");
codegenOperation.imports.add("ReadableBodyPart");
codegenOperation.imports.add("ArrayList");
codegenOperation.imports.add("DataChunk");
codegenOperation.imports.add("ByteArrayOutputStream");
codegenOperation.imports.add("IOException");
codegenOperation.imports.add("UncheckedIOException");
codegenOperation.imports.add("ByteArrayInputStream");
}
}
return codegenOperation;
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
generateYAMLSpecFile(objs);
return super.postProcessSupportingFileData(objs);
}
@Override
public String toApiName(String name) {
if (name.length() == 0) {
return "DefaultService";
}
name = sanitizeName(name);
return camelize(name) + "Service";
}
@Override
public CodegenModel fromModel(String name, Schema model) {
CodegenModel codegenModel = super.fromModel(name, model);
// remove swagger imports
codegenModel.imports.remove("ApiModelProperty");
codegenModel.imports.remove("ApiModel");
return codegenModel;
}
@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
OperationMap operations = objs.getOperations();
if (HELIDON_MP.equals(getLibrary())) {
return AbstractJavaJAXRSServerCodegen.jaxrsPostProcessOperations(objs);
}
if (operations != null && HELIDON_SE.equals(getLibrary())) {
List<CodegenOperation> ops = operations.getOperation();
for (CodegenOperation operation : ops) {
if (operation.formParams.size() > 0) {
objs.put("isFormParamsFunctions", true);
}
}
}
return objs;
}
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);
if (Boolean.TRUE.equals(model.hasEnums)) {
// Add imports for Jackson
if (additionalProperties.containsKey(JACKSON)) {
model.imports.add("JsonValue");
model.imports.add("JsonCreator");
}
}
}
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
@Override
public String getName() {
return "java-helidon-server";
}
@Override
public String getHelp() {
return "Generates a Java Helidon Server application.";
}
@Override
public void setUseBeanValidation(boolean useBeanValidation) {
this.useBeanValidation = useBeanValidation;
}
@Override
public void setPerformBeanValidation(boolean performBeanValidation) {
throw new UnsupportedOperationException("Not implemented");
}
public String getSerializationLibrary() {
return serializationLibrary;
}
public void setSerializationLibrary(String serializationLibrary) {
if (SERIALIZATION_LIBRARY_JACKSON.equalsIgnoreCase(serializationLibrary)) {
this.serializationLibrary = SERIALIZATION_LIBRARY_JACKSON;
} else if (SERIALIZATION_LIBRARY_JSONB.equalsIgnoreCase(serializationLibrary)) {
this.serializationLibrary = SERIALIZATION_LIBRARY_JSONB;
} else {
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();
}
}
@@ -0,0 +1,34 @@
# Helidon Server with OpenAPI
## Build and run
With JDK11+
```bash
mvn package
java -jar target/{{{artifactId}}}.jar
```
## Exercise the application
```
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}curl -X {{httpMethod}} {{{basePath}}}{{{path}}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
```
## Try health and metrics
```
curl -s -X GET {{{basePath}}}/health
{"outcome":"UP",...
. . .
# Prometheus Format
curl -s -X GET {{{basePath}}}/metrics
# TYPE base:gc_g1_young_generation_count gauge
. . .
# JSON Format
curl -H 'Accept: application/json' -X GET {{{basePath}}}/metrics
{"base":...
. . .
```
@@ -0,0 +1,39 @@
{{>licenseInfo}}
package {{invokerPackage}};
import com.fasterxml.jackson.databind.util.StdDateFormat;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class RFC3339DateFormat extends DateFormat {
private static final long serialVersionUID = 1L;
private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC");
private final StdDateFormat fmt = new StdDateFormat()
.withTimeZone(TIMEZONE_Z)
.withColonInTimeZone(true);
public RFC3339DateFormat() {
this.calendar = new GregorianCalendar();
}
@Override
public Date parse(String source, ParsePosition pos) {
return fmt.parse(source, pos);
}
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return fmt.format(date, toAppendTo, fieldPosition);
}
@Override
public Object clone() {
return this;
}
}
@@ -0,0 +1,53 @@
{{>licenseInfo}}
package {{invokerPackage}};
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
/**
* Class that add parsing/formatting support for Java 8+ {@code OffsetDateTime} class.
* It's generated for java clients when {@code AbstractJavaCodegen#dateLibrary} specified as {@code java8}.
*/
{{>generatedAnnotation}}
public class JavaTimeFormatter {
private DateTimeFormatter offsetDateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
/**
* Get the date format used to parse/format {@code OffsetDateTime} parameters.
* @return DateTimeFormatter
*/
public DateTimeFormatter getOffsetDateTimeFormatter() {
return offsetDateTimeFormatter;
}
/**
* Set the date format used to parse/format {@code OffsetDateTime} parameters.
* @param offsetDateTimeFormatter {@code DateTimeFormatter}
*/
public void setOffsetDateTimeFormatter(DateTimeFormatter offsetDateTimeFormatter) {
this.offsetDateTimeFormatter = offsetDateTimeFormatter;
}
/**
* Parse the given string into {@code OffsetDateTime} object.
* @param str String
* @return {@code OffsetDateTime}
*/
public OffsetDateTime parseOffsetDateTime(String str) {
try {
return OffsetDateTime.parse(str, offsetDateTimeFormatter);
} catch (DateTimeParseException e) {
throw new RuntimeException(e);
}
}
/**
* Format the given {@code OffsetDateTime} object into string.
* @param offsetDateTime {@code OffsetDateTime}
* @return {@code OffsetDateTime} in string format
*/
public String formatOffsetDateTime(OffsetDateTime offsetDateTime) {
return offsetDateTimeFormatter.format(offsetDateTime);
}
}
@@ -0,0 +1,11 @@
package {{invokerPackage}};
import {{rootJavaEEPackage}}.enterprise.context.ApplicationScoped;
import {{rootJavaEEPackage}}.ws.rs.ApplicationPath;
import {{rootJavaEEPackage}}.ws.rs.core.Application;
@ApplicationScoped
@ApplicationPath("{{{contextPath}}}")
public class RestApplication extends Application {
}
@@ -0,0 +1,72 @@
{{>licenseInfo}}
package {{invokerPackage}};
import java.util.Collection;
import java.util.Iterator;
{{>generatedAnnotation}}
public class StringUtil {
/**
* Check if the given array contains the given value (with case-insensitive comparison).
*
* @param array The array
* @param value The value to search
* @return true if the array contains the value
*/
public static boolean containsIgnoreCase(String[] array, String value) {
for (String str : array) {
if (value == null && str == null) {
return true;
}
if (value != null && value.equalsIgnoreCase(str)) {
return true;
}
}
return false;
}
/**
* Join an array of strings with the given separator.
* <p>
* Note: This might be replaced by utility method from commons-lang or guava someday
* if one of those libraries is added as dependency.
* </p>
*
* @param array The array of strings
* @param separator The separator
* @return the resulting string
*/
public static String join(String[] array, String separator) {
int len = array.length;
if (len == 0) {
return "";
}
StringBuilder out = new StringBuilder();
out.append(array[0]);
for (int i = 1; i < len; i++) {
out.append(separator).append(array[i]);
}
return out.toString();
}
/**
* Join a list of strings with the given separator.
*
* @param list The list of strings
* @param separator The separator
* @return the resulting string
*/
public static String join(Collection<String> list, String separator) {
Iterator<String> iterator = list.iterator();
StringBuilder out = new StringBuilder();
if (iterator.hasNext()) {
out.append(iterator.next());
}
while (iterator.hasNext()) {
out.append(separator).append(iterator.next());
}
return out.toString();
}
}
@@ -0,0 +1,2 @@
{{#additionalEnumTypeAnnotations}}{{{.}}}
{{/additionalEnumTypeAnnotations}}
@@ -0,0 +1,2 @@
{{#additionalModelTypeAnnotations}}{{{.}}}
{{/additionalModelTypeAnnotations}}
@@ -0,0 +1,32 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import {{rootJavaEEPackage}}.ws.rs.*;
import {{rootJavaEEPackage}}.ws.rs.core.Response;
{{#supportAsync}}
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
{{/supportAsync}}
import java.io.InputStream;
import java.util.Map;
import java.util.List;
{{#useBeanValidation}}import {{rootJavaEEPackage}}.validation.constraints.*;
import {{rootJavaEEPackage}}.validation.Valid;{{/useBeanValidation}}
@Path("{{commonPath}}"){{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
{{>generatedAnnotation}}
public {{^useAbstractClass}}interface{{/useAbstractClass}}{{#useAbstractClass}}abstract class{{/useAbstractClass}} {{classname}} {
{{#operations}}
{{#operation}}
{{>apiAbstract}}
{{/operation}}
}
{{/operations}}
@@ -0,0 +1,5 @@
@{{httpMethod}}{{#subresourceOperation}}
@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
abstract {{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}Response{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}});
@@ -0,0 +1,32 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import {{rootJavaEEPackage}}.ws.rs.*;
import {{rootJavaEEPackage}}.ws.rs.core.Response;
{{#supportAsync}}
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
{{/supportAsync}}
import java.io.InputStream;
import java.util.Map;
import java.util.List;
{{#useBeanValidation}}import {{rootJavaEEPackage}}.validation.constraints.*;
import {{rootJavaEEPackage}}.validation.Valid;{{/useBeanValidation}}
@Path("{{commonPath}}"){{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
{{>generatedAnnotation}}
public class {{classname}}Impl {{^useAbstractClass}}implements{{/useAbstractClass}}{{#useAbstractClass}}extends{{/useAbstractClass}} {{classname}} {
{{#operations}}
{{#operation}}
{{>apiMethod}}
{{/operation}}
}
{{/operations}}
@@ -0,0 +1,7 @@
@{{httpMethod}}{{#subresourceOperation}}
@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}
public {{#supportAsync}}CompletionStage<{{/supportAsync}}Response{{#supportAsync}}>{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}) {
return {{#supportAsync}}CompletableFuture.supplyAsync(() -> {{/supportAsync}}Response.ok().entity("magic!").build(){{#supportAsync}}){{/supportAsync}};
}
@@ -0,0 +1,108 @@
# {{classname}}{{#description}}
{{.}}{{/description}}
All URIs are relative to *{{basePath}}*
| Method | HTTP request | Description |
|------------- | ------------- | -------------|
{{#operations}}{{#operation}}| [**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{commonPath}}{{path}} | {{summary}} |
{{/operation}}{{/operations}}
{{#operations}}
{{#operation}}
## {{operationId}}
> {{#returnType}}{{.}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
{{summary}}{{#notes}}
{{.}}{{/notes}}
### Example
```java
// Import classes:
import {{{invokerPackage}}}.ApiClient;
import {{{invokerPackage}}}.ApiException;
import {{{invokerPackage}}}.Configuration;{{#hasAuthMethods}}
import {{{invokerPackage}}}.auth.*;{{/hasAuthMethods}}
import {{{invokerPackage}}}.models.*;
import {{{package}}}.{{{classname}}};
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("{{{basePath}}}");
{{#hasAuthMethods}}
{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
// Configure HTTP basic authorization: {{{name}}}
HttpBasicAuth {{{name}}} = (HttpBasicAuth) defaultClient.getAuthentication("{{{name}}}");
{{{name}}}.setUsername("YOUR USERNAME");
{{{name}}}.setPassword("YOUR PASSWORD");{{/isBasicBasic}}{{#isBasicBearer}}
// Configure HTTP bearer authorization: {{{name}}}
HttpBearerAuth {{{name}}} = (HttpBearerAuth) defaultClient.getAuthentication("{{{name}}}");
{{{name}}}.setBearerToken("BEARER TOKEN");{{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}
// Configure API key authorization: {{{name}}}
ApiKeyAuth {{{name}}} = (ApiKeyAuth) defaultClient.getAuthentication("{{{name}}}");
{{{name}}}.setApiKey("YOUR API KEY");
// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
//{{{name}}}.setApiKeyPrefix("Token");{{/isApiKey}}{{#isOAuth}}
// Configure OAuth2 access token for authorization: {{{name}}}
OAuth {{{name}}} = (OAuth) defaultClient.getAuthentication("{{{name}}}");
{{{name}}}.setAccessToken("YOUR ACCESS TOKEN");{{/isOAuth}}
{{/authMethods}}
{{/hasAuthMethods}}
{{{classname}}} apiInstance = new {{{classname}}}(defaultClient);
{{#allParams}}
{{{dataType}}} {{{paramName}}} = {{{example}}}; // {{{dataType}}} | {{{description}}}
{{/allParams}}
try {
{{#returnType}}{{{.}}} result = {{/returnType}}apiInstance.{{{operationId}}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}});{{#returnType}}
System.out.println(result);{{/returnType}}
} catch (ApiException e) {
System.err.println("Exception when calling {{{classname}}}#{{{operationId}}}");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
```
### Parameters
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
| Name | Type | Description | Notes |
|------------- | ------------- | ------------- | -------------|{{/-last}}{{/allParams}}
{{#allParams}}| **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{^isContainer}}{{#defaultValue}} [default to {{.}}]{{/defaultValue}}{{/isContainer}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}} |
{{/allParams}}
### Return type
{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{returnType}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}}
### Authorization
{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}}
### HTTP request headers
- **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
- **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}}
{{#responses.0}}
### HTTP response details
| Status code | Description | Response headers |
|-------------|-------------|------------------|
{{#responses}}
| **{{code}}** | {{message}} | {{#headers}} * {{baseName}} - {{description}} <br> {{/headers}}{{^headers.0}} - {{/headers.0}} |
{{/responses}}
{{/responses.0}}
{{/operation}}
{{/operations}}
@@ -0,0 +1,19 @@
{{>licenseInfo}}
package {{apiPackage}};
import {{rootJavaEEPackage}}.ws.rs.core.Response;
public class ApiException extends Exception {
private static final long serialVersionUID = 1L;
private final Response response;
public ApiException(Response response) {
super("Api response has status code " + response.getStatus());
this.response = response;
}
public Response getResponse() {
return this.response;
}
}
@@ -0,0 +1,22 @@
{{>licenseInfo}}
package {{apiPackage}};
import {{rootJavaEEPackage}}.ws.rs.core.MultivaluedMap;
import {{rootJavaEEPackage}}.ws.rs.core.Response;
import {{rootJavaEEPackage}}.ws.rs.ext.Provider;
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
@Provider
public class ApiExceptionMapper implements ResponseExceptionMapper<ApiException> {
@Override
public boolean handles(int status, MultivaluedMap<String, Object> headers) {
return status >= 400;
}
@Override
public ApiException toThrowable(Response response) {
return new ApiException(response);
}
}
@@ -0,0 +1,59 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import {{rootJavaEEPackage}}.inject.Inject;
import {{rootJavaEEPackage}}.ws.rs.client.WebTarget;
import org.junit.jupiter.api.Test;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import java.net.URL;
import java.net.MalformedURLException;
{{^fullJavaUtil}}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
{{/fullJavaUtil}}
/**
{{#appName}}
* {{{.}}} Test
*
{{/appName}}
* API tests for {{classname}}
*/
@HelidonTest
public class {{classname}}Test {
@Inject
private WebTarget target;
{{#operations}}{{#operation}}
/**
{{#summary}}
* {{summary}}
*
{{#notes}}
* {{.}}
*
{{/notes}}
{{/summary}}
* @throws ApiException if the Api call fails
*/
@Test
public void {{operationId}}Test() throws Exception {
// TODO: test validations
{{#allParams}}
{{^isFile}}{{{dataType}}} {{paramName}} = null;{{/isFile}}
{{/allParams}}
//{{#returnType}}{{{.}}} response = {{/returnType}}target.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
//{{#returnType}}assertNotNull(response);{{/returnType}}
}
{{/operation}}{{/operations}}
}
@@ -0,0 +1 @@
{{#isArray}}{{baseType}}<{{#items}}{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}{{>beanValidatedType}}{{/items}}>{{/isArray}}{{^isArray}}{{{datatypeWithEnum}}}{{/isArray}}
@@ -0,0 +1,4 @@
{{#required}}
@NotNull
{{/required}}
{{>beanValidationCore}}
@@ -0,0 +1,20 @@
{{#pattern}} @Pattern(regexp="{{{.}}}"){{/pattern}}{{!
minLength && maxLength set
}}{{#minLength}}{{#maxLength}} @Size(min={{minLength}},max={{maxLength}}){{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}} @Size(min={{minLength}}){{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}} @Size(max={{.}}){{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}} @Size(min={{minItems}},max={{maxItems}}){{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}} @Size(min={{minItems}}){{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}} @Size(max={{.}}){{/maxItems}}{{/minItems}}{{!
check for integer or long / all others=decimal type with @Decimal*
isInteger set
}}{{#isInteger}}{{#minimum}} @Min({{.}}){{/minimum}}{{#maximum}} @Max({{.}}){{/maximum}}{{/isInteger}}{{!
isLong set
}}{{#isLong}}{{#minimum}} @Min({{.}}L){{/minimum}}{{#maximum}} @Max({{.}}L){{/maximum}}{{/isLong}}{{!
Not Integer, not Long => we have a decimal value!
}}{{^isInteger}}{{^isLong}}{{#minimum}} @DecimalMin({{#exclusiveMinimum}}value={{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}},inclusive=false{{/exclusiveMinimum}}){{/minimum}}{{#maximum}} @DecimalMax({{#exclusiveMaximum}}value={{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}},inclusive=false{{/exclusiveMaximum}}){{/maximum}}{{/isLong}}{{/isInteger}}
@@ -0,0 +1 @@
{{#required}} @NotNull{{/required}}{{>beanValidationCore}}
@@ -0,0 +1 @@
{{! PathParam is always required, no @NotNull necessary }}{{>beanValidationCore}}
@@ -0,0 +1 @@
{{#required}} @NotNull{{/required}}{{>beanValidationCore}}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
version="2.0"
bean-discovery-mode="annotated">
</beans>
@@ -0,0 +1 @@
{{#isBodyParam}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{/isBodyParam}}
@@ -0,0 +1,79 @@
plugins {
id 'java'
id 'application'
}
group = '{{{groupId}}}'
version = '{{{artifactVersion}}}'
{{#appDescription}}
description = """{{.}}"""
{{/appDescription}}
sourceCompatibility = 11
targetCompatibility = 11
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
ext {
helidonVersion = '{{{helidonVersion}}}'
mainClass='io.helidon.microprofile.cdi.Main'
}
test {
useJUnitPlatform()
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
// import Helidon BOM
implementation enforcedPlatform("io.helidon:helidon-dependencies:${project.helidonVersion}")
implementation 'io.helidon.microprofile.bundles:helidon-microprofile-core'
implementation 'io.helidon.microprofile.cdi:helidon-microprofile-cdi'
implementation '{{rootJavaEEPackage}}.enterprise:{{rootJavaEEPackage}}.enterprise.cdi-api'
implementation '{{rootJavaEEPackage}}.ws.rs:{{rootJavaEEPackage}}.ws.rs-api'
{{#jackson}}
implementation 'org.glassfish.jersey.media:jersey-media-json-jackson'
{{/jackson}}
{{#jsonb}}
implementation 'org.glassfish.jersey.media:jersey-media-json-binding'
implementation '{{rootJavaEEPackage}}.json.bind:{{rootJavaEEPackage}}.json.bind-api'
{{/jsonb}}
testImplementation 'junit:junit'
testImplementation 'io.helidon.microprofile.tests:helidon-microprofile-tests-junit5'
}
// define a custom task to copy all dependencies in the runtime classpath
// into build/libs/libs
// uses built-in Copy
task copyLibs(type: Copy) {
from configurations.runtimeClasspath
into 'build/libs/libs'
}
// add it as a dependency of built-in task 'assemble'
copyLibs.dependsOn jar
assemble.dependsOn copyLibs
// default jar configuration
// set the main classpath
// add each jar under build/libs/libs into the classpath
jar {
archiveFileName = "${project.name}.jar"
manifest {
attributes ('Main-Class': "${project.mainClass}",
'Class-Path': configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ')
)
}
}
application {
mainClass = "${project.mainClass}"
}
@@ -0,0 +1 @@
{{#isCookieParam}}@CookieParam("{{baseName}}"){{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{^isContainer}}{{#defaultValue}} @DefaultValue("{{{.}}}"){{/defaultValue}}{{/isContainer}} {{{dataType}}} {{paramName}}{{/isCookieParam}}
@@ -0,0 +1,48 @@
{{>additionalEnumTypeAnnotations}}public enum {{datatypeWithEnum}} {
{{#allowableValues}}
{{#enumVars}}{{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
{{/allowableValues}}
private {{dataType}} value;
{{datatypeWithEnum}} ({{dataType}} v) {
value = v;
}
public {{dataType}} value() {
return value;
}
@Override
{{#jackson}}@JsonValue{{/jackson}}
public String toString() {
return String.valueOf(value);
}
/**
* Convert a String into {{dataType}}, as specified in the
* <a href="https://download.oracle.com/otndocs/jcp/jaxrs-2_0-fr-eval-spec/index.html">See JAX RS 2.0 Specification, section 3.2, p. 12</a>
*/
public static {{datatypeWithEnum}} fromString(String s) {
for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
// using Objects.toString() to be safe if value type non-object type
// because types like 'int' etc. will be auto-boxed
if (java.util.Objects.toString(b.value).equals(s)) {
return b;
}
}
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected string value '" + s + "'");{{/isNullable}}
}
{{#jackson}}@JsonCreator{{/jackson}}
public static {{datatypeWithEnum}} fromValue({{dataType}} value) {
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
if (b.value.equals(value)) {
return b;
}
}
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/isNullable}}
}
}
@@ -0,0 +1,61 @@
{{#jackson}}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
{{/jackson}}
{{#jsonb}}
import {{rootJavaEEPackage}}.json.bind.annotation.JsonbCreator;
{{/jsonb}}
/**
* {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
*/
{{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} {
{{#gson}}
{{#allowableValues}}{{#enumVars}}
@SerializedName({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}})
{{{name}}}({{{value}}}){{^-last}},
{{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}}
{{/gson}}
{{^gson}}
{{#allowableValues}}{{#enumVars}}
{{{name}}}({{{value}}}){{^-last}},
{{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}}
{{/gson}}
private {{{dataType}}} value;
{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) {
this.value = value;
}
/**
* Convert a String into {{dataType}}, as specified in the
* <a href="https://download.oracle.com/otndocs/jcp/jaxrs-2_0-fr-eval-spec/index.html">See JAX RS 2.0 Specification, section 3.2, p. 12</a>
*/
public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromString(String s) {
for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
// using Objects.toString() to be safe if value type non-object type
// because types like 'int' etc. will be auto-boxed
if (java.util.Objects.toString(b.value).equals(s)) {
return b;
}
}
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected string value '" + s + "'");{{/isNullable}}
}
@Override
{{#jackson}}@JsonValue{{/jackson}}
public String toString() {
return String.valueOf(value);
}
{{#jackson}}@JsonCreator{{/jackson}}{{#jsonb}}@JsonbCreator{{/jsonb}}
public static {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} value) {
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
if (b.value.equals(value)) {
return b;
}
}
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/isNullable}}
}
}
@@ -0,0 +1 @@
{{#isFormParam}}{{^isFile}}@FormParam(value = "{{baseName}}") {{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}} @FormParam(value = "{{baseName}}") InputStream {{paramName}}InputStream{{/isFile}}{{/isFormParam}}
@@ -0,0 +1 @@
@{{rootJavaEEPackage}}.annotation.Generated(value = "{{generatorClass}}"{{^hideGenerationTimestamp}}, date = "{{generatedDate}}"{{/hideGenerationTimestamp}})
@@ -0,0 +1 @@
{{#isHeaderParam}}@HeaderParam("{{baseName}}"){{#useBeanValidation}}{{>beanValidationHeaderParams}}{{/useBeanValidation}} {{#defaultValue}} @DefaultValue("{{{.}}}"){{/defaultValue}} {{{dataType}}} {{paramName}}{{/isHeaderParam}}
@@ -0,0 +1,25 @@
# Example Logging Configuration File
# For more information see $JAVA_HOME/jre/lib/logging.properties
## Send messages to the console
handlers=io.helidon.common.HelidonConsoleHandler
#
## HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
#
## Global logging level. Can be overridden by specific loggers
.level=INFO
# Quiet Weld
org.jboss.level=WARNING
#
# Component specific log levels
#io.helidon.webserver.level=INFO
#io.helidon.config.level=INFO
#io.helidon.security.level=INFO
#io.helidon.microprofile.level=INFO
#io.helidon.common.level=INFO
#io.netty.level=INFO
#org.glassfish.jersey.level=INFO
#org.jboss.weld=INFO
@@ -0,0 +1,11 @@
# Microprofile server properties
# Application properties. This is the default greeting
app.greeting=Hello
# Microprofile server properties
server.port=8080
server.host=0.0.0.0
# Enable the optional MicroProfile Metrics REST.request metrics
metrics.rest-request.enabled=true
@@ -0,0 +1,23 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
{{#serializableModel}}
import java.io.Serializable;
{{/serializableModel}}
{{#useBeanValidation}}
import {{rootJavaEEPackage}}.validation.constraints.*;
import {{rootJavaEEPackage}}.validation.Valid;
{{/useBeanValidation}}
{{#models}}
{{#model}}
{{#isEnum}}
{{>enumOuterClass}}
{{/isEnum}}
{{^isEnum}}
{{>pojo}}
{{/isEnum}}
{{/model}}
{{/models}}
@@ -0,0 +1,73 @@
/**
* {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
*/
{{#jsonb}}
@JsonbTypeSerializer({{datatypeWithEnum}}.Serializer.class)
@JsonbTypeDeserializer({{datatypeWithEnum}}.Deserializer.class)
{{/jsonb}}
{{#withXml}}
@XmlType(name="{{datatypeWithEnum}}")
@XmlEnum({{dataType}}.class)
{{/withXml}}
{{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} {
{{#allowableValues}}
{{#enumVars}}
{{#enumDescription}}
/**
* {{.}}
*/
{{/enumDescription}}
{{#withXml}}
@XmlEnumValue({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}})
{{/withXml}}
{{{name}}}({{{value}}}){{^-last}},
{{/-last}}{{#-last}};{{/-last}}
{{/enumVars}}
{{/allowableValues}}
private {{{dataType}}} value;
{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}({{{dataType}}} value) {
this.value = value;
}
{{#jackson}}@JsonValue{{/jackson}}
public {{{dataType}}} getValue() {
return value;
}
@Override
public String toString() {
return String.valueOf(value);
}
{{#jackson}}@JsonCreator{{/jackson}}
public static {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} value) {
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
if (b.value.equals(value)) {
return b;
}
}
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/isNullable}}
}
{{#jsonb}}
public static final class Deserializer implements JsonbDeserializer<{{datatypeWithEnum}}> {
@Override
public {{datatypeWithEnum}} deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
if (String.valueOf(b.value).equals(parser.getString())) {
return b;
}
}
{{#useNullForUnknownEnumValue}}return null;{{/useNullForUnknownEnumValue}}{{^useNullForUnknownEnumValue}}throw new IllegalArgumentException("Unexpected value '" + parser.getString() + "'");{{/useNullForUnknownEnumValue}}
}
}
public static final class Serializer implements JsonbSerializer<{{datatypeWithEnum}}> {
@Override
public void serialize({{datatypeWithEnum}} obj, JsonGenerator generator, SerializationContext ctx) {
generator.write(obj.value);
}
}
{{/jsonb}}
}
@@ -0,0 +1,4 @@
{{#models}}{{#model}}
{{#isEnum}}{{>enum_outer_doc}}{{/isEnum}}{{^isEnum}}{{>pojo_doc}}{{/isEnum}}
{{/model}}{{/models}}
@@ -0,0 +1 @@
{{{openapi-yaml}}}
@@ -0,0 +1 @@
{{#isPathParam}}@PathParam("{{baseName}}"){{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}} {{{dataType}}} {{paramName}}{{/isPathParam}}
@@ -0,0 +1,161 @@
{{#jsonb}}
import java.lang.reflect.Type;
import {{rootJavaEEPackage}}.json.bind.annotation.JsonbTypeDeserializer;
import {{rootJavaEEPackage}}.json.bind.annotation.JsonbTypeSerializer;
import {{rootJavaEEPackage}}.json.bind.serializer.DeserializationContext;
import {{rootJavaEEPackage}}.json.bind.serializer.JsonbDeserializer;
import {{rootJavaEEPackage}}.json.bind.serializer.JsonbSerializer;
import {{rootJavaEEPackage}}.json.bind.serializer.SerializationContext;
import {{rootJavaEEPackage}}.json.stream.JsonGenerator;
import {{rootJavaEEPackage}}.json.stream.JsonParser;
import {{rootJavaEEPackage}}.json.bind.annotation.JsonbProperty;
{{#vendorExtensions.x-has-readonly-properties}}
import {{rootJavaEEPackage}}.json.bind.annotation.JsonbCreator;
{{/vendorExtensions.x-has-readonly-properties}}
{{/jsonb}}
{{#jackson}}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
{{/jackson}}
{{#description}}
/**
* {{{.}}}
**/
{{/description}}
{{>additionalModelTypeAnnotations}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{#vendorExtensions.x-implements}}{{#-first}} implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{#vars}}{{#isEnum}}{{^isContainer}}
{{>enumClass}}{{/isContainer}}{{#isContainer}}{{#mostInnerItems}}
{{>enumClass}}{{/mostInnerItems}}{{/isContainer}}{{/isEnum}}
{{#description}}
/**
* {{{.}}}
**/
{{/description}}
{{#vendorExtensions.x-field-extra-annotation}}
{{{vendorExtensions.x-field-extra-annotation}}}
{{/vendorExtensions.x-field-extra-annotation}}
{{#isContainer}}
private {{{datatypeWithEnum}}} {{name}}{{#required}} = {{{defaultValue}}}{{/required}}{{^required}} = null{{/required}};
{{/isContainer}}
{{^isContainer}}
private {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
{{/isContainer}}
{{/vars}}
{{#vendorExtensions.x-has-readonly-properties}}{{^withXml}}
public {{classname}}() {
}
{{#jsonb}}@JsonbCreator{{/jsonb}}{{#jackson}}@JsonCreator{{/jackson}}
public {{classname}}(
{{#readOnlyVars}}
{{#jsonb}}@JsonbProperty("{{baseName}}") {{{datatypeWithEnum}}} {{name}}{{^-last}}, {{/-last}}{{/jsonb}}
{{#jackson}}@JsonProperty(value="{{baseName}}") {{{datatypeWithEnum}}} {{name}}{{^-last}}, {{/-last}}{{/jackson}}
{{/readOnlyVars}}
) {
{{#readOnlyVars}}
this.{{name}} = {{name}};
{{/readOnlyVars}}
}
{{/withXml}}{{/vendorExtensions.x-has-readonly-properties}}
{{#vars}}
/**
{{#description}}
* {{.}}
{{/description}}
{{^description}}
* Get {{name}}
{{/description}}
{{#minimum}}
* minimum: {{.}}
{{/minimum}}
{{#maximum}}
* maximum: {{.}}
{{/maximum}}
* @return {{name}}
{{#deprecated}}
* @deprecated
{{/deprecated}}
**/
{{#deprecated}}
@Deprecated
{{/deprecated}}
{{#vendorExtensions.x-extra-annotation}}
{{{vendorExtensions.x-extra-annotation}}}
{{/vendorExtensions.x-extra-annotation}}
{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} {{#withXml}}{{#isEnum}}{{^isArray}}{{^isMap}}public {{dataType}} {{getter}}() {
if ({{name}} == null) {
return null;
}
return {{name}}.value();
}{{/isMap}}{{/isArray}}{{/isEnum}}{{/withXml}}{{^withXml}}{{#isEnum}}{{^isArray}}{{^isMap}}public {{datatypeWithEnum}} {{getter}}() {
return {{name}};
}{{/isMap}}{{/isArray}}{{/isEnum}}{{/withXml}}{{#isEnum}}{{#isArray}}public {{{datatypeWithEnum}}} {{getter}}() {
return {{name}};
}{{/isArray}}{{/isEnum}}{{#isEnum}}{{#isMap}}public {{{datatypeWithEnum}}} {{getter}}() {
return {{name}};
}{{/isMap}}{{/isEnum}}{{^isEnum}}public {{{datatypeWithEnum}}} {{getter}}() {
return {{name}};
}{{/isEnum}}
{{^isReadOnly}}
/**
* Set {{name}}
**/
{{#vendorExtensions.x-setter-extra-annotation}} {{{vendorExtensions.x-setter-extra-annotation}}}
{{/vendorExtensions.x-setter-extra-annotation}}public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
this.{{name}} = {{name}};
}
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
this.{{name}} = {{name}};
return this;
}
{{#isArray}}
public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
this.{{name}}.add({{name}}Item);
return this;
}
{{/isArray}}
{{#isMap}}
public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
this.{{name}}.put(key, {{name}}Item);
return this;
}
{{/isMap}}
{{/isReadOnly}}
{{/vars}}
/**
* Create a string representation of this pojo.
**/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class {{classname}} {\n");
{{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}}
{{#vars}}sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n");
{{/vars}}sb.append("}");
return sb.toString();
}
/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private static String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
}
@@ -0,0 +1,37 @@
# {{#vendorExtensions.x-is-one-of-interface}}Interface {{/vendorExtensions.x-is-one-of-interface}}{{classname}}
{{#description}}{{&description}}
{{/description}}
{{^vendorExtensions.x-is-one-of-interface}}
## Properties
| Name | Type | Description | Notes |
|------------ | ------------- | ------------- | -------------|
{{#vars}}|**{{name}}** | {{#isEnum}}[**{{datatypeWithEnum}}**](#{{datatypeWithEnum}}){{/isEnum}}{{^isEnum}}{{#isContainer}}{{#isArray}}{{#items}}{{#isModel}}[{{/isModel}}{{/items}}**{{baseType}}{{#items}}&lt;{{dataType}}&gt;**{{#isModel}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isModel}}{{/items}}{{/isArray}}{{#isMap}}{{#items}}{{#isModel}}[{{/isModel}}**Map&lt;String, {{dataType}}&gt;**{{#isModel}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isModel}}{{/items}}{{/isMap}}{{/isContainer}}{{^isContainer}}{{#isModel}}[{{/isModel}}**{{dataType}}**{{#isModel}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isModel}}{{/isContainer}}{{/isEnum}} | {{description}} | {{^required}} [optional]{{/required}}{{#isReadOnly}} [readonly]{{/isReadOnly}} |
{{/vars}}
{{#vars}}{{#isEnum}}
## Enum: {{datatypeWithEnum}}
| Name | Value |
|---- | -----|{{#allowableValues}}{{#enumVars}}
| {{name}} | {{value}} |{{/enumVars}}{{/allowableValues}}
{{/isEnum}}{{/vars}}
{{#vendorExtensions.x-implements.0}}
## Implemented Interfaces
{{#vendorExtensions.x-implements}}
* {{{.}}}
{{/vendorExtensions.x-implements}}
{{/vendorExtensions.x-implements.0}}
{{/vendorExtensions.x-is-one-of-interface}}
{{#vendorExtensions.x-is-one-of-interface}}
## Implementing Classes
{{#oneOf}}
* {{{.}}}
{{/oneOf}}
{{/vendorExtensions.x-is-one-of-interface}}
@@ -0,0 +1,100 @@
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>{{groupId}}</groupId>
<parent>
<groupId>io.helidon.applications</groupId>
<artifactId>helidon-mp</artifactId>
<version>{{{helidonVersion}}}</version>
<relativePath/>
</parent>
<artifactId>{{artifactId}}</artifactId>
<name>{{artifactId}}</name>
{{#appDescription}}
<description>{{.}}</description>
{{/appDescription}}
<version>{{artifactVersion}}</version>
<packaging>jar</packaging>
{{#openApiNullable}}
<properties>
<version.jackson.databind.nullable>0.2.3</version.jackson.databind.nullable>
</properties>
{{/openApiNullable}}
<dependencies>
<dependency>
<groupId>io.helidon.microprofile.bundles</groupId>
<artifactId>helidon-microprofile-core</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.cdi</groupId>
<artifactId>helidon-microprofile-cdi</artifactId>
</dependency>
<dependency>
<groupId>{{x-helidon-rootJavaEEDepPrefix}}.enterprise</groupId>
<artifactId>{{x-helidon-rootJavaEEDepPrefix}}.enterprise.cdi-api</artifactId>
</dependency>
<dependency>
<groupId>{{x-helidon-rootJavaEEDepPrefix}}.ws.rs</groupId>
<artifactId>{{x-helidon-rootJavaEEDepPrefix}}.ws.rs-api</artifactId>
</dependency>
{{#openApiNullable}}
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${version.jackson.databind.nullable}</version>
</dependency>
{{/openApiNullable}}
{{#jackson}}
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
{{/jackson}}
{{#jsonb}}
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
</dependency>
<dependency>
<groupId>{{x-helidon-rootJavaEEDepPrefix}}.json.bind</groupId>
<artifactId>{{x-helidon-rootJavaEEDepPrefix}}.json.bind-api</artifactId>
</dependency>
{{/jsonb}}
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-libs</id>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<executions>
<execution>
<id>make-index</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1 @@
{{#isQueryParam}}@QueryParam("{{baseName}}"){{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}} {{^isContainer}}{{#defaultValue}}@DefaultValue("{{{.}}}") {{/defaultValue}}{{/isContainer}}{{{dataType}}} {{paramName}}{{/isQueryParam}}
@@ -0,0 +1 @@
{{#returnContainer}}{{#isMap}}Map<String, {{{returnType}}}>{{/isMap}}{{#isArray}}{{{returnContainer}}}<{{{returnType}}}>{{/isArray}}{{/returnContainer}}{{^returnContainer}}{{{returnType}}}{{/returnContainer}}
@@ -0,0 +1,17 @@
{{#jackson}}
@JsonIgnoreProperties(
value = "{{{discriminator.propertyBaseName}}}", // ignore manually set {{{discriminator.propertyBaseName}}}, it will be automatically generated by Jackson during serialization
allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization
)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
{{#discriminator.mappedModels}}
{{#-first}}
@JsonSubTypes({
{{/-first}}
@JsonSubTypes.Type(value = {{modelName}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{mappingName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"),
{{#-last}}
})
{{/-last}}
{{/discriminator.mappedModels}}
{{/jackson}}
@@ -0,0 +1,11 @@
/*
* {{{appName}}}
* {{{appDescription}}}
*
* {{#version}}The version of the OpenAPI document: {{{.}}}{{/version}}
* {{#infoEmail}}Contact: {{{.}}}{{/infoEmail}}
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
@@ -0,0 +1,19 @@
# Example Logging Configuration File
# For more information see $JAVA_HOME/jre/lib/logging.properties
# Send messages to the console
handlers=io.helidon.common.HelidonConsoleHandler
# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
# Global logging level. Can be overridden by specific loggers
.level=INFO
# Component specific log levels
#io.helidon.webserver.level=INFO
#io.helidon.config.level=INFO
#io.helidon.security.level=INFO
#io.helidon.common.level=INFO
#io.netty.level=INFO
@@ -0,0 +1,47 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import org.junit.jupiter.api.Test;
{{#fullJavaUtil}}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
{{/fullJavaUtil}}
/**
* Model tests for {{classname}}
*/
public class {{classname}}Test {
{{#models}}
{{#model}}
{{^vendorExtensions.x-is-one-of-interface}}
{{^isEnum}}
private final {{classname}} model = new {{classname}}();
{{/isEnum}}
/**
* Model tests for {{classname}}
*/
@Test
public void test{{classname}}() {
// TODO: test {{classname}}
}
{{#allVars}}
/**
* Test the property '{{name}}'
*/
@Test
public void {{name}}Test() {
// TODO: test {{name}}
}
{{/allVars}}
{{/vendorExtensions.x-is-one-of-interface}}
{{/model}}
{{/models}}
}
@@ -0,0 +1 @@
{{{openapi-yaml}}}
@@ -0,0 +1 @@
package {{invokerPackage}};
@@ -0,0 +1 @@
rootProject.name = '{{artifactId}}'