From 74c600c87709cf854827eb9d5a26c9dc1cad8b10 Mon Sep 17 00:00:00 2001 From: spericas Date: Fri, 23 Sep 2022 17:11:14 -0500 Subject: [PATCH] Add Helidon client generator MicroProfile library Java class and resources Signed-off-by: spericas --- .../languages/JavaHelidonClientCodegen.java | 531 ++++++++++++++++++ .../libraries/mp/JavaTimeFormatter.mustache | 53 ++ .../libraries/mp/RFC3339DateFormat.mustache | 46 ++ .../client/libraries/mp/StringUtil.mustache | 72 +++ .../mp/additionalEnumTypeAnnotations.mustache | 2 + .../additionalModelTypeAnnotations.mustache | 2 + .../client/libraries/mp/api.mustache | 61 ++ .../client/libraries/mp/apiOperation.mustache | 28 + .../client/libraries/mp/api_doc.mustache | 55 ++ .../libraries/mp/api_exception.mustache | 19 + .../mp/api_exception_mapper.mustache | 22 + .../client/libraries/mp/api_test.mustache | 64 +++ .../libraries/mp/auth/ApiKeyAuth.mustache | 66 +++ .../libraries/mp/auth/HttpBasicAuth.mustache | 42 ++ .../libraries/mp/auth/HttpBearerAuth.mustache | 49 ++ .../client/libraries/mp/bodyParams.mustache | 1 + .../client/libraries/mp/cookieParams.mustache | 1 + .../client/libraries/mp/enumClass.mustache | 46 ++ .../libraries/mp/enumOuterClass.mustache | 39 ++ .../libraries/mp/enum_outer_doc.mustache | 7 + .../client/libraries/mp/formParams.mustache | 1 + .../libraries/mp/generatedAnnotation.mustache | 1 + .../client/libraries/mp/headerParams.mustache | 1 + .../libraries/mp/jackson_annotations.mustache | 19 + .../client/libraries/mp/licenseInfo.mustache | 11 + .../client/libraries/mp/model.mustache | 19 + .../libraries/mp/modelInnerEnum.mustache | 95 ++++ .../client/libraries/mp/model_doc.mustache | 4 + .../client/libraries/mp/model_test.mustache | 49 ++ .../libraries/mp/oneof_interface.mustache | 6 + .../client/libraries/mp/openapi.mustache | 1 + .../client/libraries/mp/pathParams.mustache | 1 + .../client/libraries/mp/pojo.mustache | 155 +++++ .../client/libraries/mp/pojo_doc.mustache | 37 ++ .../client/libraries/mp/pom.mustache | 90 +++ .../client/libraries/mp/queryParams.mustache | 1 + .../client/libraries/mp/returnTypes.mustache | 4 + .../libraries/mp/typeInfoAnnotation.mustache | 17 + 38 files changed, 1718 insertions(+) create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonClientCodegen.java create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/JavaTimeFormatter.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/RFC3339DateFormat.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/StringUtil.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalEnumTypeAnnotations.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalModelTypeAnnotations.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/apiOperation.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_doc.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception_mapper.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_test.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/ApiKeyAuth.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBasicAuth.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBearerAuth.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/bodyParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/cookieParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumClass.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumOuterClass.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enum_outer_doc.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/formParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/generatedAnnotation.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/headerParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/jackson_annotations.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/licenseInfo.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/modelInnerEnum.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_doc.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_test.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/oneof_interface.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/openapi.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pathParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo_doc.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pom.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/queryParams.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/returnTypes.mustache create mode 100644 modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/typeInfoAnnotation.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonClientCodegen.java new file mode 100644 index 00000000000..6f2de171dd7 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaHelidonClientCodegen.java @@ -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 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> 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 modifiable = new ArrayList<>(); + modifiable.add(new SupportingFile("pom.mustache", "", "pom.xml")); + modifiable.add(new SupportingFile("README.mustache", "", "README.md")); + List 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 modifiable = new ArrayList<>(); + modifiable.add(new SupportingFile("pom.mustache", "", "pom.xml")); + modifiable.add(new SupportingFile("README.mustache", "", "README.md")); + + List 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 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> imports = objs.getImports(); + List> implImports = new ArrayList<>(imports); + + Set requiredImplImportClassNames = new HashSet<>(); + for (CodegenOperation op : objs.getOperations().getOperation()) { + requiredImplImportClassNames.addAll((Set) op.vendorExtensions.get(X_HELIDON_REQUIRED_IMPL_IMPORTS)); + } + + Set missingImportClassNames = new TreeSet<>(requiredImplImportClassNames); + imports.stream() + .map(m -> m.get("classname")) + .forEach(missingImportClassNames::remove); + + missingImportClassNames.forEach(c -> { + Map 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 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 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 models = objs.getModels(); + + if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) { + List> 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 enumVars : (List>) 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 importsSet = new HashMap<>(); + importsSet.put("import", "java.util.Set"); + imports.add(importsSet); + Map importsHashSet = new HashMap<>(); + importsHashSet.put("import", "java.util.HashSet"); + imports.add(importsHashSet); + } + + } + + if (addImports) { + Map 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 entry : imports2Classnames.entrySet()) { + cm.imports.add(entry.getKey()); + Map 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 postProcessSupportingFileData(Map 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> imports) { + for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo", "JsonIgnoreProperties")) { + Map oneImport = new HashMap<>(); + oneImport.put("import", importMapping.get(i)); + if (!imports.contains(oneImport)) { + imports.add(oneImport); + } + } + } + + @Override + public List getSupportedVendorExtensions() { + List extensions = super.getSupportedVendorExtensions(); + extensions.add(VendorExtension.X_WEBCLIENT_BLOCKING); + return extensions; + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/JavaTimeFormatter.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/JavaTimeFormatter.mustache new file mode 100644 index 00000000000..f3fb34e559c --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/JavaTimeFormatter.mustache @@ -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); + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/RFC3339DateFormat.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/RFC3339DateFormat.mustache new file mode 100644 index 00000000000..311616a4ef1 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/RFC3339DateFormat.mustache @@ -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(); + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/StringUtil.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/StringUtil.mustache new file mode 100644 index 00000000000..e3d5d6e9088 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/StringUtil.mustache @@ -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. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @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 list, String separator) { + Iterator 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(); + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalEnumTypeAnnotations.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalEnumTypeAnnotations.mustache new file mode 100644 index 00000000000..aa524798b42 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalEnumTypeAnnotations.mustache @@ -0,0 +1,2 @@ +{{#additionalEnumTypeAnnotations}}{{{.}}} +{{/additionalEnumTypeAnnotations}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalModelTypeAnnotations.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalModelTypeAnnotations.mustache new file mode 100644 index 00000000000..f4871c02cc2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/additionalModelTypeAnnotations.mustache @@ -0,0 +1,2 @@ +{{#additionalModelTypeAnnotations}}{{{.}}} +{{/additionalModelTypeAnnotations}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api.mustache new file mode 100644 index 00000000000..6367b03ed23 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api.mustache @@ -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}} + *

{{{.}}} + {{/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}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/apiOperation.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/apiOperation.mustache new file mode 100644 index 00000000000..97adb0ea285 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/apiOperation.mustache @@ -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; + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_doc.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_doc.mustache new file mode 100644 index 00000000000..ba9757d1edb --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_doc.mustache @@ -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}}
{{/headers}}{{^headers.0}} - {{/headers.0}} | +{{/responses}} +{{/responses.0}} + +{{/operation}} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception.mustache new file mode 100644 index 00000000000..d9fb5ee91d8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception.mustache @@ -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; + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception_mapper.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception_mapper.mustache new file mode 100644 index 00000000000..ac4db62e8b8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_exception_mapper.mustache @@ -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 { + + @Override + public boolean handles(int status, MultivaluedMap headers) { + return status >= 400; + } + + @Override + public ApiException toThrowable(Response response) { + return new ApiException(response); + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_test.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_test.mustache new file mode 100644 index 00000000000..cbe676a88ba --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/api_test.mustache @@ -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}} +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/ApiKeyAuth.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/ApiKeyAuth.mustache new file mode 100644 index 00000000000..991ae235003 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/ApiKeyAuth.mustache @@ -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 queryParams, Map headerParams, Map 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); + } + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBasicAuth.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBasicAuth.mustache new file mode 100644 index 00000000000..b5c72de6e7e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBasicAuth.mustache @@ -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 queryParams, Map headerParams, Map 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))); + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBearerAuth.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBearerAuth.mustache new file mode 100644 index 00000000000..322281f8716 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/auth/HttpBearerAuth.mustache @@ -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 queryParams, Map headerParams, Map 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; + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/bodyParams.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/bodyParams.mustache new file mode 100644 index 00000000000..c7d1abfe527 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/bodyParams.mustache @@ -0,0 +1 @@ +{{#isBodyParam}}{{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/cookieParams.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/cookieParams.mustache new file mode 100644 index 00000000000..fea14348d7f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/cookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}@CookieParam("{{baseName}}"){{^isContainer}}{{#defaultValue}} @DefaultValue("{{{.}}}"){{/defaultValue}}{{/isContainer}} {{#useSwaggerAnnotations}}{{#description}} @ApiParam("{{.}}"){{/description}}{{/useSwaggerAnnotations}} {{{dataType}}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumClass.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumClass.mustache new file mode 100644 index 00000000000..d32efebf489 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumClass.mustache @@ -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}} +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumOuterClass.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumOuterClass.mustache new file mode 100644 index 00000000000..39417c635f8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enumOuterClass.mustache @@ -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}} + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enum_outer_doc.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enum_outer_doc.mustache new file mode 100644 index 00000000000..20c512aaeae --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/enum_outer_doc.mustache @@ -0,0 +1,7 @@ +# {{classname}} + +## Enum + +{{#allowableValues}}{{#enumVars}} +* `{{name}}` (value: `{{{value}}}`) +{{/enumVars}}{{/allowableValues}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/formParams.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/formParams.mustache new file mode 100644 index 00000000000..fa85e0c8947 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/formParams.mustache @@ -0,0 +1 @@ +{{#isFormParam}}@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isFormParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/generatedAnnotation.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/generatedAnnotation.mustache new file mode 100644 index 00000000000..356a48872aa --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/generatedAnnotation.mustache @@ -0,0 +1 @@ +@{{rootJavaEEPackage}}.annotation.Generated(value = "{{generatorClass}}"{{^hideGenerationTimestamp}}, date = "{{generatedDate}}"{{/hideGenerationTimestamp}}) \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/headerParams.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/headerParams.mustache new file mode 100644 index 00000000000..25d690c90ed --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/headerParams.mustache @@ -0,0 +1 @@ +{{#isHeaderParam}}@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/jackson_annotations.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/jackson_annotations.mustache new file mode 100644 index 00000000000..ccde126f54e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/jackson_annotations.mustache @@ -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}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/licenseInfo.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/licenseInfo.mustache new file mode 100644 index 00000000000..be193d0c4fe --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/licenseInfo.mustache @@ -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. + */ diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model.mustache new file mode 100644 index 00000000000..ad4e98b8a45 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model.mustache @@ -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}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/modelInnerEnum.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/modelInnerEnum.mustache new file mode 100644 index 00000000000..a9c99783fd0 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/modelInnerEnum.mustache @@ -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}} + } diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_doc.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_doc.mustache new file mode 100644 index 00000000000..9a7fe146a4e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_doc.mustache @@ -0,0 +1,4 @@ +{{#models}}{{#model}} + +{{#isEnum}}{{>enum_outer_doc}}{{/isEnum}}{{^isEnum}}{{>pojo_doc}}{{/isEnum}} +{{/model}}{{/models}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_test.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_test.mustache new file mode 100644 index 00000000000..92c1e7ee2e3 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/model_test.mustache @@ -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}} +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/oneof_interface.mustache new file mode 100644 index 00000000000..02deb483d5f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/oneof_interface.mustache @@ -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}} +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/openapi.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/openapi.mustache new file mode 100644 index 00000000000..34fbb53f331 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/openapi.mustache @@ -0,0 +1 @@ +{{{openapi-yaml}}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pathParams.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pathParams.mustache new file mode 100644 index 00000000000..ba153467a65 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pathParams.mustache @@ -0,0 +1 @@ +{{#isPathParam}}@PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isPathParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo.mustache new file mode 100644 index 00000000000..84115fa7d02 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo.mustache @@ -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 "); + } +} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo_doc.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo_doc.mustache new file mode 100644 index 00000000000..bae0bc48cdd --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pojo_doc.mustache @@ -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}}<{{dataType}}>**{{#isModel}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isModel}}{{/items}}{{/isArray}}{{#isMap}}{{#items}}{{#isModel}}[{{/isModel}}**Map<String, {{dataType}}>**{{#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}} diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pom.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pom.mustache new file mode 100644 index 00000000000..6deab37c810 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/pom.mustache @@ -0,0 +1,90 @@ + + 4.0.0 + {{groupId}} + + io.helidon.applications + helidon-mp + {{helidonVersion}} + + + {{artifactId}} + {{artifactId}} + {{artifactVersion}} + {{artifactUrl}} + {{artifactDescription}} + jar + + + + io.helidon.microprofile.rest-client + helidon-microprofile-rest-client + + + io.helidon.microprofile.config + helidon-microprofile-config + + + org.glassfish.jersey.ext.cdi + jersey-cdi1x + + + {{x-helidon-rootJavaEEDepPrefix}}.enterprise + {{x-helidon-rootJavaEEDepPrefix}}.enterprise.cdi-api + + + {{x-helidon-rootJavaEEDepPrefix}}.json + {{x-helidon-rootJavaEEDepPrefix}}.json-api + +{{#jackson}} + + org.glassfish.jersey.media + jersey-media-json-jackson + + + org.openapitools + jackson-databind-nullable + 0.2.2 + +{{/jackson}} +{{#jsonb}} + + org.glassfish.jersey.media + jersey-media-json-binding + + + {{x-helidon-rootJavaEEDepPrefix}}.json.bind + {{x-helidon-rootJavaEEDepPrefix}}.json.bind-api + +{{/jsonb}} + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + org.jboss.jandex + jandex-maven-plugin + + + make-index + + + + + + diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/queryParams.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/queryParams.mustache new file mode 100644 index 00000000000..4b1a980896f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/queryParams.mustache @@ -0,0 +1 @@ +{{#isQueryParam}}@QueryParam("{{baseName}}") {{^isContainer}}{{#defaultValue}}@DefaultValue("{{{.}}}") {{/defaultValue}}{{/isContainer}}{{{dataType}}} {{paramName}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/returnTypes.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/returnTypes.mustache new file mode 100644 index 00000000000..32f96a90472 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/returnTypes.mustache @@ -0,0 +1,4 @@ +{{#useGenericResponse}}Response{{/useGenericResponse}}{{! non-generic response: +}}{{^useGenericResponse}}{{! +}}{{{returnType}}}{{! +}}{{/useGenericResponse}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/typeInfoAnnotation.mustache b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/typeInfoAnnotation.mustache new file mode 100644 index 00000000000..c833321ebfa --- /dev/null +++ b/modules/openapi-generator/src/main/resources/java-helidon/client/libraries/mp/typeInfoAnnotation.mustache @@ -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}}