Add Helidon client generator MicroProfile library Java class and resources

Signed-off-by: spericas <santiago.pericasgeertsen@oracle.com>
This commit is contained in:
spericas 2022-09-23 17:11:14 -05:00 committed by tim.quinn@oracle.com
parent 6be539db83
commit 74c600c877
38 changed files with 1718 additions and 0 deletions

View File

@ -0,0 +1,531 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
* 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.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
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.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenParameter;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenResponse;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.VendorExtension;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.meta.features.GlobalFeature;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.model.OperationsMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.openapitools.codegen.CodegenConstants.SERIALIZATION_LIBRARY;
public class JavaHelidonClientCodegen extends JavaHelidonCommonCodegen {
private final Logger LOGGER = LoggerFactory.getLogger(JavaHelidonClientCodegen.class);
private static final String X_HELIDON_REQUIRED_IMPL_IMPORTS = "x-helidon-requiredImplImports";
private static final String X_HELIDON_IMPL_IMPORTS = "x-helidon-implImports";
public static final String CONFIG_KEY = "configKey";
protected String configKey = null;
protected boolean useBeanValidation = false;
protected boolean performBeanValidation = false;
protected boolean useGzipFeature = false;
protected boolean caseInsensitiveResponseHeaders = false;
protected Path invokerFolder;
protected Path apiFolder;
protected String serializationLibrary = null;
/**
* Constructor for this generator. Uses the embedded template dir to find common templates
* shared between Helidon client and server generators.
*
* @see org.openapitools.codegen.templating.GeneratorTemplateContentLocator#getFullTemplatePath
*/
public JavaHelidonClientCodegen() {
// beta for now
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.BETA)
.build();
// TODO: Move GlobalFeature.ParameterizedServer to library: jersey after moving featureSet to generatorMetadata
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.includeGlobalFeatures(GlobalFeature.ParameterizedServer)
);
outputFolder = "generated-code" + File.separator + "java";
embeddedTemplateDir = "java-helidon" + File.separator + "common"; // use embedded for common
templateDir = "java-helidon" + File.separator + "client";
invokerPackage = "org.openapitools.client";
artifactId = "openapi-java-client";
apiPackage = invokerPackage + ".api";
modelPackage = invokerPackage + ".model";
updateOption(CodegenConstants.INVOKER_PACKAGE, getInvokerPackage());
updateOption(CodegenConstants.ARTIFACT_ID, getArtifactId());
updateOption(CodegenConstants.API_PACKAGE, apiPackage);
updateOption(CodegenConstants.MODEL_PACKAGE, modelPackage);
modelTestTemplateFiles.put("model_test.mustache", ".java");
cliOptions.add(CliOption.newString(CONFIG_KEY, "Config key in @RegisterRestClient. Default to none."));
supportedLibraries.put(HELIDON_MP, "Helidon MP Client");
supportedLibraries.put(HELIDON_SE, "Helidon SE Client");
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY,
"library template (sub-template) to use");
libraryOption.setEnum(supportedLibraries);
libraryOption.setDefault(HELIDON_MP);
cliOptions.add(libraryOption);
setLibrary(HELIDON_MP); // default
CliOption serializationLibrary = new CliOption(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); // default
removeUnusedOptions();
// Ensure the OAS 3.x discriminator mappings include any descendent schemas that allOf
// inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values,
// and the discriminator mapping schemas in the OAS document.
this.setLegacyDiscriminatorBehavior(false);
}
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "java-helidon-client";
}
@Override
public String getHelp() {
return "Generates a Helidon MP or SE client";
}
@Override
public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co,
Map<String, List<CodegenOperation>> operations) {
super.addOperationToGroup(tag, resourcePath, operation, co, operations);
if (HELIDON_MP.equals(getLibrary())) {
co.subresourceOperation = !co.path.isEmpty();
}
}
@Override
public String apiFilename(String templateName, String tag) {
if (templateName.contains("_impl")) {
String suffix = apiTemplateFiles().get(templateName);
return apiFileFolder() + File.separator + toApiFilename(tag) + "Impl" + suffix;
}
return super.apiFilename(templateName, tag);
}
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY)) {
setSerializationLibrary(additionalProperties.get(SERIALIZATION_LIBRARY).toString());
}
if (additionalProperties.containsKey(CONFIG_KEY)) {
setConfigKey(additionalProperties.get(CONFIG_KEY).toString());
}
String invokerPath = invokerPackage.replace('.', File.separatorChar);
invokerFolder = Paths.get(sourceFolder, invokerPath);
apiFolder = Paths.get(outputFolder).relativize(Paths.get(apiFileFolder()));
if (isLibrary(HELIDON_MP)) {
String apiExceptionFolder = Paths.get(sourceFolder,
apiPackage().replace('.', File.separatorChar)).toString();
List<SupportingFile> modifiable = new ArrayList<>();
modifiable.add(new SupportingFile("pom.mustache", "", "pom.xml"));
modifiable.add(new SupportingFile("README.mustache", "", "README.md"));
List<SupportingFile> unmodifiable = new ArrayList<>();
unmodifiable.add(new SupportingFile("api_exception.mustache", apiExceptionFolder, "ApiException.java"));
unmodifiable.add(new SupportingFile("api_exception_mapper.mustache", apiExceptionFolder, "ApiExceptionMapper.java"));
if (additionalProperties.containsKey("jsr310")) {
unmodifiable.add(new SupportingFile("JavaTimeFormatter.mustache",
invokerFolder.toString(), "JavaTimeFormatter.java"));
}
processSupportingFiles(modifiable, unmodifiable);
} else if (isLibrary(HELIDON_SE)) {
apiTemplateFiles.put("api_impl.mustache", ".java");
importMapping.put("StringJoiner", "java.util.StringJoiner");
importMapping.put("WebClientRequestHeaders", "io.helidon.webclient.WebClientRequestHeaders");
importMapping.put("Pair", invokerPackage + ".Pair");
List<SupportingFile> modifiable = new ArrayList<>();
modifiable.add(new SupportingFile("pom.mustache", "", "pom.xml"));
modifiable.add(new SupportingFile("README.mustache", "", "README.md"));
List<SupportingFile> unmodifiable = new ArrayList<>();
unmodifiable.add(new SupportingFile("ApiResponse.mustache", invokerFolder.toString(), "ApiResponse.java"));
unmodifiable.add(new SupportingFile("ApiResponseBase.mustache", invokerFolder.toString(), "ApiResponseBase.java"));
unmodifiable.add(new SupportingFile("ApiClient.mustache", invokerFolder.toString(), "ApiClient.java"));
unmodifiable.add(new SupportingFile("Pair.mustache", invokerFolder.toString(), "Pair.java"));
unmodifiable.add(new SupportingFile("ResponseType.mustache", apiFolder.toString(), "ResponseType.java"));
processSupportingFiles(modifiable, unmodifiable);
}
else {
LOGGER.error("Unknown library option (-l/--library): {}", 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.toString(), "RFC3339DateFormat.java"));
break;
case SERIALIZATION_LIBRARY_JSONB:
openApiNullable = false; // for Jackson only
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;
}
}
/**
* 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 src = projectFolder.resolve(invokerFolder);
return pom.toFile().exists() && src.toFile().exists();
}
@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
if (isLibrary(HELIDON_MP)) {
super.postProcessOperationsWithModels(objs, allModels);
return AbstractJavaJAXRSServerCodegen.jaxrsPostProcessOperations(objs);
} else {
// Compute the imports to declare in the generated API impl class.
List<Map<String, String>> imports = objs.getImports();
List<Map<String, String>> implImports = new ArrayList<>(imports);
Set<String> requiredImplImportClassNames = new HashSet<>();
for (CodegenOperation op : objs.getOperations().getOperation()) {
requiredImplImportClassNames.addAll((Set) op.vendorExtensions.get(X_HELIDON_REQUIRED_IMPL_IMPORTS));
}
Set<String> missingImportClassNames = new TreeSet<>(requiredImplImportClassNames);
imports.stream()
.map(m -> m.get("classname"))
.forEach(missingImportClassNames::remove);
missingImportClassNames.forEach(c -> {
Map<String, String> singleImportMap = new HashMap<>();
singleImportMap.put("classname", c);
singleImportMap.put("import", Objects.requireNonNull(importMapping.get(c), "no mapping for " + c));
implImports.add(singleImportMap);
});
objs.put(X_HELIDON_IMPL_IMPORTS, implImports);
return objs;
}
}
@Override
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List<Server> servers) {
CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
// We use two templates, one for the API interface and one for the impl class.
// Add to the normal imports for this operation only those imports used in both
// the API and the impl. Create a vendor extension on the operation to record the
// additional imports needed for the implementation class.
Set<String> requiredImplImports = new TreeSet<>();
if (op.isArray) {
op.imports.add("List");
}
if (op.isMap) {
op.imports.add("Map");
}
if (op.getHasQueryParams()) {
requiredImplImports.add("List");
requiredImplImports.add("ArrayList");
requiredImplImports.add("Pair");
}
if (op.getHasHeaderParams()) {
requiredImplImports.add("WebClientRequestHeaders");
}
if (op.getHasFormParams()) {
requiredImplImports.add("StringJoiner");
}
if (op.getHasCookieParams()) {
requiredImplImports.add("StringJoiner");
}
if (op.bodyParams.stream().anyMatch(JavaHelidonClientCodegen::checkIsArray)
|| op.allParams.stream().anyMatch(JavaHelidonClientCodegen::checkIsArray)
|| op.responses.stream().anyMatch(CodegenResponse::getIsArray)) {
requiredImplImports.add("List");
op.imports.add("List");
}
if (op.bodyParams.stream().anyMatch(JavaHelidonClientCodegen::checkIsMap)
|| op.allParams.stream().anyMatch(JavaHelidonClientCodegen::checkIsMap)
|| op.responses.stream().anyMatch(CodegenResponse::getIsMap)) {
requiredImplImports.add("Map");
op.imports.add("Map");
}
op.vendorExtensions.put(X_HELIDON_REQUIRED_IMPL_IMPORTS, requiredImplImports);
return op;
}
private static boolean checkIsArray(CodegenParameter p) {
return p.isArray || !(p.getSchema() != null && p.getSchema().getIsArray());
}
private static boolean checkIsMap(CodegenParameter p) {
return p.isMap || !(p.getSchema() != null && p.getSchema().getIsMap());
}
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);
if (!BooleanUtils.toBoolean(model.isEnum)
&& additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) {
model.imports.add("JsonProperty");
model.imports.add("JsonValue");
model.imports.add("JsonInclude");
model.imports.add("JsonTypeName");
} else if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) {
model.imports.add("JsonValue");
model.imports.add("JsonCreator");
}
if (HELIDON_MP.equals(getLibrary())) {
model.imports.remove("ApiModelProperty");
model.imports.remove("ApiModel");
model.imports.remove("JsonSerialize");
model.imports.remove("ToStringSerializer");
} else if (HELIDON_SE.equals(getLibrary())) {
// TODO check for SE-specifics
model.imports.remove("ApiModelProperty");
model.imports.remove("ApiModel");
model.imports.remove("JsonSerialize");
model.imports.remove("ToStringSerializer");
}
if ("set".equals(property.containerType) && !JACKSON.equals(serializationLibrary)) {
// clean-up
model.imports.remove("JsonDeserialize");
property.vendorExtensions.remove("x-setter-extra-annotation");
}
}
@Override
public CodegenModel fromModel(String name, Schema model) {
CodegenModel codegenModel = super.fromModel(name, model);
if (isLibrary(HELIDON_MP)) {
if (codegenModel.imports.contains("ApiModel")) {
// Remove io.swagger.annotations.ApiModel import
codegenModel.imports.remove("ApiModel");
}
} else if (isLibrary(HELIDON_SE)) {
if (codegenModel.imports.contains("ApiModel")) {
// Remove io.swagger.annotations.ApiModel import
codegenModel.imports.remove("ApiModel");
}
}
return codegenModel;
}
@SuppressWarnings("unchecked")
@Override
public ModelsMap postProcessModels(ModelsMap objs) {
objs = super.postProcessModels(objs);
List<ModelMap> models = objs.getModels();
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) {
List<Map<String, String>> imports = objs.getImports();
for (ModelMap mo : models) {
CodegenModel cm = mo.getModel();
boolean addImports = false;
for (CodegenProperty var : cm.vars) {
if (this.openApiNullable) {
boolean isOptionalNullable = Boolean.FALSE.equals(var.required) && Boolean.TRUE.equals(var.isNullable);
// only add JsonNullable and related imports to optional and nullable values
addImports |= isOptionalNullable;
var.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable);
}
if (Boolean.TRUE.equals(var.getVendorExtensions().get("x-enum-as-string"))) {
// treat enum string as just string
var.datatypeWithEnum = var.dataType;
if (StringUtils.isNotEmpty(var.defaultValue)) { // has default value
String defaultValue = var.defaultValue.substring(var.defaultValue.lastIndexOf('.') + 1);
for (Map<String, Object> enumVars : (List<Map<String, Object>>) var.getAllowableValues().get("enumVars")) {
if (defaultValue.equals(enumVars.get("name"))) {
// update default to use the string directly instead of enum string
var.defaultValue = (String) enumVars.get("value");
}
}
}
// add import for Set, HashSet
cm.imports.add("Set");
Map<String, String> importsSet = new HashMap<>();
importsSet.put("import", "java.util.Set");
imports.add(importsSet);
Map<String, String> importsHashSet = new HashMap<>();
importsHashSet.put("import", "java.util.HashSet");
imports.add(importsHashSet);
}
}
if (addImports) {
Map<String, String> imports2Classnames = new HashMap<>();
imports2Classnames.put("JsonNullable", "org.openapitools.jackson.nullable.JsonNullable");
imports2Classnames.put("NoSuchElementException", "java.util.NoSuchElementException");
imports2Classnames.put("JsonIgnore", "com.fasterxml.jackson.annotation.JsonIgnore");
for (Map.Entry<String, String> entry : imports2Classnames.entrySet()) {
cm.imports.add(entry.getKey());
Map<String, String> importsItem = new HashMap<>();
importsItem.put("import", entry.getValue());
imports.add(importsItem);
}
}
}
}
return objs;
}
public void setConfigKey(String configKey) {
this.configKey = configKey;
}
public void setUseBeanValidation(boolean useBeanValidation) {
this.useBeanValidation = useBeanValidation;
}
public void setPerformBeanValidation(boolean performBeanValidation) {
this.performBeanValidation = performBeanValidation;
}
public void setUseGzipFeature(boolean useGzipFeature) {
this.useGzipFeature = useGzipFeature;
}
public void setCaseInsensitiveResponseHeaders(final Boolean caseInsensitiveResponseHeaders) {
this.caseInsensitiveResponseHeaders = caseInsensitiveResponseHeaders;
}
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);
}
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
generateYAMLSpecFile(objs);
return super.postProcessSupportingFileData(objs);
}
@Override
public String toApiVarName(String name) {
String apiVarName = super.toApiVarName(name);
if (reservedWords.contains(apiVarName)) {
apiVarName = escapeReservedWord(apiVarName);
}
return apiVarName;
}
@Override
public void addImportsToOneOfInterface(List<Map<String, String>> imports) {
for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo", "JsonIgnoreProperties")) {
Map<String, String> oneImport = new HashMap<>();
oneImport.put("import", importMapping.get(i));
if (!imports.contains(oneImport)) {
imports.add(oneImport);
}
}
}
@Override
public List<VendorExtension> getSupportedVendorExtensions() {
List<VendorExtension> extensions = super.getSupportedVendorExtensions();
extensions.add(VendorExtension.X_WEBCLIENT_BLOCKING);
return extensions;
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,46 @@
{{>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.text.DecimalFormat;
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();
this.numberFormat = new DecimalFormat();
}
@Override
public Date parse(String source) {
return parse(source, new ParsePosition(0));
}
@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 super.clone();
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,2 @@
{{#additionalEnumTypeAnnotations}}{{{.}}}
{{/additionalEnumTypeAnnotations}}

View File

@ -0,0 +1,2 @@
{{#additionalModelTypeAnnotations}}{{{.}}}
{{/additionalModelTypeAnnotations}}

View File

@ -0,0 +1,61 @@
{{>licenseInfo}}
package {{package}};
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import {{rootJavaEEPackage}}.ws.rs.*;
import {{rootJavaEEPackage}}.ws.rs.core.Response;
import {{rootJavaEEPackage}}.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
{{#imports}}import {{import}};
{{/imports}}
{{#appName}}
/**
* {{{appName}}}
*
{{#appDescription}}
* <p>{{{.}}}
{{/appDescription}}
*/
{{/appName}}
@RegisterRestClient{{#configKey}}(configKey="{{configKey}}"){{/configKey}}
@RegisterProvider(ApiExceptionMapper.class)
@Path("{{#useAnnotatedBasePath}}{{contextPath}}{{/useAnnotatedBasePath}}{{commonPath}}")
public interface {{classname}} {
{{#operations}}
{{#operation}}
{{#summary}}
/**
* {{summary}}
{{#notes}}
* {{.}}
{{/notes}}
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
*/
{{/summary}}
{{#isDeprecated}}
@Deprecated
{{/isDeprecated}}
@{{httpMethod}}
{{#subresourceOperation}}@Path("{{{path}}}"){{/subresourceOperation}}
{{#hasConsumes}}
@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} })
{{/hasConsumes}}
{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} })
{{/hasProduces}}
{{{returnType}}}{{^returnType}}void{{/returnType}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException, ProcessingException;
{{/operation}}
}
{{/operations}}

View File

@ -0,0 +1,28 @@
{{>licenseInfo}}
package {{invokerPackage}};
import io.swagger.v3.oas.models.Operation;
public class ApiOperation {
private final String path;
private final String method;
private final Operation operation;
public ApiOperation(String path, String method, Operation operation) {
this.path = path;
this.method = method;
this.operation = operation;
}
public Operation getOperation() {
return operation;
}
public String getPath() {
return path;
}
public String getMethod() {
return method;
}
}

View File

@ -0,0 +1,55 @@
# {{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}}
### 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}}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,64 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
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}}
*/
public class {{classname}}Test {
private static {{classname}} client;
private static final String baseUrl = "http://localhost:8080";
@BeforeAll
public static void setup() throws MalformedURLException {
client = RestClientBuilder.newBuilder()
.baseUrl(new URL(baseUrl))
.register(ApiException.class)
.build({{classname}}.class);
}
{{#operations}}{{#operation}}
/**
{{#summary}}
* {{summary}}
*
{{#notes}}
* {{.}}
*
{{/notes}}
{{/summary}}
* @throws ApiException
* if the Api call fails
*/
@Test
public void {{operationId}}Test() throws Exception {
{{#allParams}}
{{/allParams}}
//{{#returnType}}{{{.}}} response = {{/returnType}}client.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
//{{#returnType}}assertNotNull(response);{{/returnType}}
}
{{/operation}}{{/operations}}
}

View File

@ -0,0 +1,66 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import java.util.Map;
import java.util.List;
{{>generatedAnnotation}}
public class ApiKeyAuth implements Authentication {
private final String location;
private final String paramName;
private String apiKey;
private String apiKeyPrefix;
public ApiKeyAuth(String location, String paramName) {
this.location = location;
this.paramName = paramName;
}
public String getLocation() {
return location;
}
public String getParamName() {
return paramName;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getApiKeyPrefix() {
return apiKeyPrefix;
}
public void setApiKeyPrefix(String apiKeyPrefix) {
this.apiKeyPrefix = apiKeyPrefix;
}
@Override
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams, Map<String, String> cookieParams) {
if (apiKey == null) {
return;
}
String value;
if (apiKeyPrefix != null) {
value = apiKeyPrefix + " " + apiKey;
} else {
value = apiKey;
}
if ("query".equals(location)) {
queryParams.add(new Pair(paramName, value));
} else if ("header".equals(location)) {
headerParams.put(paramName, value);
} else if ("cookie".equals(location)) {
cookieParams.put(paramName, value);
}
}
}

View File

@ -0,0 +1,42 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.List;
{{>generatedAnnotation}}
public class HttpBasicAuth implements Authentication {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams, Map<String, String> cookieParams) {
if (username == null && password == null) {
return;
}
String str = (username == null ? "" : username) + ":" + (password == null ? "" : password);
headerParams.put("Authorization", "Basic " + Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8)));
}
}

View File

@ -0,0 +1,49 @@
{{>licenseInfo}}
package {{invokerPackage}}.auth;
import {{invokerPackage}}.Pair;
import java.util.Map;
import java.util.List;
{{>generatedAnnotation}}
public class HttpBearerAuth implements Authentication {
private final String scheme;
private String bearerToken;
public HttpBearerAuth(String scheme) {
this.scheme = scheme;
}
/**
* Gets the token, which together with the scheme, will be sent as the value of the Authorization header.
*
* @return The bearer token
*/
public String getBearerToken() {
return bearerToken;
}
/**
* Sets the token, which together with the scheme, will be sent as the value of the Authorization header.
*
* @param bearerToken The bearer token to send in the Authorization header
*/
public void setBearerToken(String bearerToken) {
this.bearerToken = bearerToken;
}
@Override
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams, Map<String, String> cookieParams) {
if(bearerToken == null) {
return;
}
headerParams.put("Authorization", (scheme != null ? upperCaseBearer(scheme) + " " : "") + bearerToken);
}
private static String upperCaseBearer(String scheme) {
return ("bearer".equalsIgnoreCase(scheme)) ? "Bearer" : scheme;
}
}

View File

@ -0,0 +1 @@
{{#isBodyParam}}{{{dataType}}} {{paramName}}{{/isBodyParam}}

View File

@ -0,0 +1 @@
{{#isCookieParam}}@CookieParam("{{baseName}}"){{^isContainer}}{{#defaultValue}} @DefaultValue("{{{.}}}"){{/defaultValue}}{{/isContainer}} {{#useSwaggerAnnotations}}{{#description}} @ApiParam("{{.}}"){{/description}}{{/useSwaggerAnnotations}} {{{dataType}}} {{paramName}}{{/isCookieParam}}

View File

@ -0,0 +1,46 @@
{{#jsonb}}
@JsonbTypeSerializer({{datatypeWithEnum}}.Serializer.class)
@JsonbTypeDeserializer({{datatypeWithEnum}}.Deserializer.class)
{{/jsonb}}
{{>additionalEnumTypeAnnotations}}public enum {{datatypeWithEnum}} {
{{#allowableValues}}
{{#enumVars}}{{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
{{/allowableValues}}
{{dataType}} value;
{{datatypeWithEnum}} ({{dataType}} v) {
value = v;
}
public {{dataType}} value() {
return value;
}
@Override
public String toString() {
return String.valueOf(value);
}
{{#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}}
}

View File

@ -0,0 +1,39 @@
{{#jackson}}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
{{/jackson}}
/**
* {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
*/
{{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} {
{{#allowableValues}}{{#enumVars}}
{{{name}}}({{{value}}}){{^-last}},
{{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}}
private {{{dataType}}} value;
{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) {
this.value = value;
}
@Override
{{#jackson}}
@JsonValue
{{/jackson}}
public String toString() {
return String.valueOf(value);
}
{{#jackson}}
@JsonCreator
{{/jackson}}
public static {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue(String text) {
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
if (String.valueOf(b.value).equals(text)) {
return b;
}
}
{{#useNullForUnknownEnumValue}}return null;{{/useNullForUnknownEnumValue}}{{^useNullForUnknownEnumValue}}throw new IllegalArgumentException("Unexpected value '" + text + "'");{{/useNullForUnknownEnumValue}}
}
}

View File

@ -0,0 +1,7 @@
# {{classname}}
## Enum
{{#allowableValues}}{{#enumVars}}
* `{{name}}` (value: `{{{value}}}`)
{{/enumVars}}{{/allowableValues}}

View File

@ -0,0 +1 @@
{{#isFormParam}}@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isFormParam}}

View File

@ -0,0 +1 @@
@{{rootJavaEEPackage}}.annotation.Generated(value = "{{generatorClass}}"{{^hideGenerationTimestamp}}, date = "{{generatedDate}}"{{/hideGenerationTimestamp}})

View File

@ -0,0 +1 @@
{{#isHeaderParam}}@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isHeaderParam}}

View File

@ -0,0 +1,19 @@
{{!
If this is map and items are nullable, make sure that nulls are included.
To determine what JsonInclude.Include method to use, consider the following:
* If the field is required, always include it, even if it is null.
* Else use custom behaviour, IOW use whatever is defined on the object mapper
}}
@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
@JsonInclude({{#isMap}}{{#items.isNullable}}content = JsonInclude.Include.ALWAYS, {{/items.isNullable}}{{/isMap}}value = JsonInclude.Include.{{#required}}ALWAYS{{/required}}{{^required}}USE_DEFAULTS{{/required}})
{{#withXml}}
{{^isContainer}}
@JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{.}}", {{/xmlNamespace}}localName = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}")
{{/isContainer}}
{{#isContainer}}
{{#isXmlWrapped}}
// items.xmlName={{items.xmlName}}
@JacksonXmlElementWrapper(useWrapping = {{isXmlWrapped}}, {{#xmlNamespace}}namespace="{{.}}", {{/xmlNamespace}}localName = "{{#items.xmlName}}{{items.xmlName}}{{/items.xmlName}}{{^items.xmlName}}{{items.baseName}}{{/items.xmlName}}")
{{/isXmlWrapped}}
{{/isContainer}}
{{/withXml}}

View File

@ -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.
*/

View File

@ -0,0 +1,19 @@
{{>licenseInfo}}
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
{{#serializableModel}}
import java.io.Serializable;
{{/serializableModel}}
{{#models}}
{{#model}}
{{#isEnum}}
{{>enumOuterClass}}
{{/isEnum}}
{{^isEnum}}
{{>pojo}}
{{/isEnum}}
{{/model}}
{{/models}}

View File

@ -0,0 +1,95 @@
/**
* {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
*/
{{#gson}}
@JsonAdapter({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.Adapter.class)
{{/gson}}
{{#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}}
}
{{#gson}}
public static class Adapter extends TypeAdapter<{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}> {
@Override
public void write(final JsonWriter jsonWriter, final {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} enumeration) throws IOException {
jsonWriter.value(enumeration.getValue());
}
@Override
public {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException {
{{^isNumber}}{{{dataType}}}{{/isNumber}}{{#isNumber}}String{{/isNumber}} value = {{#isFloat}}(float){{/isFloat}} jsonReader.{{#isNumber}}nextString(){{/isNumber}}{{#isInteger}}nextInt(){{/isInteger}}{{^isNumber}}{{^isInteger}}{{#isFloat}}nextDouble{{/isFloat}}{{^isFloat}}next{{{dataType}}}{{/isFloat}}(){{/isInteger}}{{/isNumber}};
return {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.fromValue({{#isNumber}}new BigDecimal({{/isNumber}}value{{#isNumber}}){{/isNumber}});
}
}
{{/gson}}
{{#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}}
}

View File

@ -0,0 +1,4 @@
{{#models}}{{#model}}
{{#isEnum}}{{>enum_outer_doc}}{{/isEnum}}{{^isEnum}}{{>pojo_doc}}{{/isEnum}}
{{/model}}{{/models}}

View File

@ -0,0 +1,49 @@
{{>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}}
}

View File

@ -0,0 +1,6 @@
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{#discriminator}}
public {{propertyType}} {{propertyGetter}}();
{{/discriminator}}
}

View File

@ -0,0 +1 @@
{{{openapi-yaml}}}

View File

@ -0,0 +1 @@
{{#isPathParam}}@PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isPathParam}}

View File

@ -0,0 +1,155 @@
{{#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}}
{{#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}}{{#jsonb}}
public {{classname}}() {
}
@JsonbCreator
public {{classname}}(
{{#readOnlyVars}}
@JsonbProperty("{{baseName}}") {{{datatypeWithEnum}}} {{name}}{{^-last}}, {{/-last}}
{{/readOnlyVars}}
) {
{{#readOnlyVars}}
this.{{name}} = {{name}};
{{/readOnlyVars}}
}
{{/jsonb}}{{/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}}
{{#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 ");
}
}

View File

@ -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}}

View File

@ -0,0 +1,90 @@
<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>
<version>{{artifactVersion}}</version>
<url>{{artifactUrl}}</url>
<description>{{artifactDescription}}</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>io.helidon.microprofile.rest-client</groupId>
<artifactId>helidon-microprofile-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.config</groupId>
<artifactId>helidon-microprofile-config</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x</artifactId>
</dependency>
<dependency>
<groupId>{{x-helidon-rootJavaEEDepPrefix}}.enterprise</groupId>
<artifactId>{{x-helidon-rootJavaEEDepPrefix}}.enterprise.cdi-api</artifactId>
</dependency>
<dependency>
<groupId>{{x-helidon-rootJavaEEDepPrefix}}.json</groupId>
<artifactId>{{x-helidon-rootJavaEEDepPrefix}}.json-api</artifactId>
</dependency>
{{#jackson}}
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.2</version>
</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>
</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>

View File

@ -0,0 +1 @@
{{#isQueryParam}}@QueryParam("{{baseName}}") {{^isContainer}}{{#defaultValue}}@DefaultValue("{{{.}}}") {{/defaultValue}}{{/isContainer}}{{{dataType}}} {{paramName}}{{/isQueryParam}}

View File

@ -0,0 +1,4 @@
{{#useGenericResponse}}Response{{/useGenericResponse}}{{! non-generic response:
}}{{^useGenericResponse}}{{!
}}{{{returnType}}}{{!
}}{{/useGenericResponse}}

View File

@ -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}}