All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.openapi.generator.JavaMicronautClientCodegen Maven / Gradle / Ivy

/*
 * Copyright 2017-2023 original authors
 *
 * 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 io.micronaut.openapi.generator;

import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenParameter;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.GeneratorMetadata;
import org.openapitools.codegen.meta.Stability;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import static io.micronaut.openapi.generator.Utils.processMultipartBody;
import static io.micronaut.openapi.generator.Utils.readListOfStringsProperty;

/**
 * The generator for creating Micronaut clients.
 */
@SuppressWarnings("checkstyle:DesignForExtension")
public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen {

    public static final String OPT_CONFIGURE_AUTH = "configureAuth";
    public static final String OPT_CONFIGURE_AUTH_FILTER_PATTERN = "configureAuthFilterPattern";
    public static final String OPT_CONFIGURE_CLIENT_ID = "configureClientId";
    public static final String OPT_CLIENT_PATH = "clientPath";
    public static final String ADDITIONAL_CLIENT_TYPE_ANNOTATIONS = "additionalClientTypeAnnotations";
    public static final String AUTHORIZATION_FILTER_PATTERN = "authorizationFilterPattern";
    public static final String BASE_PATH_SEPARATOR = "basePathSeparator";
    public static final String CLIENT_ID = "clientId";

    public static final String NAME = "java-micronaut-client";

    protected boolean configureAuthorization;
    protected List additionalClientTypeAnnotations;
    protected String authorizationFilterPattern;
    protected String basePathSeparator = ".";
    protected String clientId;
    protected boolean clientPath;

    JavaMicronautClientCodegen() {

        title = "OpenAPI Micronaut Client";

        generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
            .stability(Stability.STABLE)
            .build();
        additionalProperties.put("client", "true");

        cliOptions.add(CliOption.newBoolean(OPT_CONFIGURE_AUTH, "Configure all the authorization methods as specified in the file", configureAuthorization));
        cliOptions.add(CliOption.newString(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS, "Additional annotations for client type(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)"));
        cliOptions.add(CliOption.newString(AUTHORIZATION_FILTER_PATTERN, "Configure the authorization filter pattern for the client. Generally defined when generating clients from multiple specification files"));
        cliOptions.add(CliOption.newString(BASE_PATH_SEPARATOR, "Configure the separator to use between the application name and base path when referencing the property").defaultValue(basePathSeparator));
        cliOptions.add(CliOption.newString(CLIENT_ID, "Configure the service ID for the Client"));
        cliOptions.add(CliOption.newBoolean(OPT_CLIENT_PATH, "Generate code with @Client annotation path attribute", clientPath));

        typeMapping.put("file", "byte[]");

        typeMapping.put("responseFile", "ByteBuffer");
        importMapping.put("ByteBuffer", "io.micronaut.core.io.buffer.ByteBuffer");

        importMapping.put("MultipartBody", "io.micronaut.http.client.multipart.MultipartBody");
    }

    @Override
    public CodegenType getTag() {
        return CodegenType.CLIENT;
    }

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public String getHelp() {
        return "Generates a Java Micronaut Client.";
    }

    private void postProcessMultipartParam(CodegenOperation op, List params, Collection removedParams) {
        var pair = processMultipartBody(op, params, false);
        var multipartParam = pair.getLeft();
        if (multipartParam != null) {
            setParameterExampleValue(multipartParam);
        }
        removedParams.addAll(pair.getRight());
    }

    @Override
    public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) {
        objs = super.postProcessOperationsWithModels(objs, allModels);

        OperationMap operations = objs.getOperations();
        List operationList = operations.getOperation();

        var removedParams = new HashSet();

        for (CodegenOperation op : operationList) {
            postProcessMultipartParam(op, op.bodyParams, removedParams);
            postProcessMultipartParam(op, op.allParams, removedParams);

            op.notNullableParams.removeIf(p -> removedParams.contains(p.paramName));
            op.requiredParams.removeIf(p -> removedParams.contains(p.paramName));
            op.optionalParams.removeIf(p -> removedParams.contains(p.paramName));
            op.requiredAndNotNullableParams.removeIf(p -> removedParams.contains(p.paramName));
            if (op.vendorExtensions.containsKey("originalParams")) {
                ((List) op.vendorExtensions.get("originalParams")).removeIf(p -> removedParams.contains(p.paramName));
            }

            if (!removedParams.isEmpty()) {
                objs.getImports().add(Map.of("import", "io.micronaut.http.client.multipart.MultipartBody", "classname", "MultipartBody"));
            }

            var hasMultipleParams = !op.allParams.isEmpty();
            var hasNotBodyParam = hasMultipleParams;

            for (var param : op.allParams) {
                param.vendorExtensions.put("hasNotBodyParam", hasNotBodyParam);
                param.vendorExtensions.put("hasMultipleParams", hasMultipleParams);
            }
        }

        return objs;
    }

    @Override
    public void processOpts() {
        super.processOpts();

        if (additionalProperties.containsKey(OPT_CONFIGURE_AUTH)) {
            configureAuthorization = convertPropertyToBoolean(OPT_CONFIGURE_AUTH);
        }
        writePropertyBack(OPT_CONFIGURE_AUTH, configureAuthorization);

        // Write property that is present in server
        writePropertyBack(OPT_USE_AUTH, true);

        writePropertyBack(OPT_CONFIGURE_AUTH_FILTER_PATTERN, false);
        writePropertyBack(OPT_CONFIGURE_CLIENT_ID, false);

        final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");

        // Authorization files
        if (configureAuthorization) {
            final String authFolder = invokerFolder + "/auth";
            supportingFiles.add(new SupportingFile("client/auth/Authorization.mustache", authFolder, "Authorization.java"));
            supportingFiles.add(new SupportingFile("client/auth/AuthorizationBinder.mustache", authFolder, "AuthorizationBinder.java"));
            supportingFiles.add(new SupportingFile("client/auth/Authorizations.mustache", authFolder, "Authorizations.java"));
            supportingFiles.add(new SupportingFile("client/auth/AuthorizationFilter.mustache", authFolder, "AuthorizationFilter.java"));
            final String authConfigurationFolder = authFolder + "/configuration";
            supportingFiles.add(new SupportingFile("client/auth/configuration/ApiKeyAuthConfiguration.mustache", authConfigurationFolder, "ApiKeyAuthConfiguration.java"));
            supportingFiles.add(new SupportingFile("client/auth/configuration/ConfigurableAuthorization.mustache", authConfigurationFolder, "ConfigurableAuthorization.java"));
            supportingFiles.add(new SupportingFile("client/auth/configuration/HttpBasicAuthConfiguration.mustache", authConfigurationFolder, "HttpBasicAuthConfiguration.java"));

            var authorizationFilterPattern = additionalProperties.get(AUTHORIZATION_FILTER_PATTERN);
            if (authorizationFilterPattern != null) {
                this.authorizationFilterPattern = authorizationFilterPattern.toString();
            }
            if (this.authorizationFilterPattern != null) {
                writePropertyBack(OPT_CONFIGURE_AUTH_FILTER_PATTERN, true);
            }
            writePropertyBack(AUTHORIZATION_FILTER_PATTERN, this.authorizationFilterPattern);
        }

        if (additionalProperties.containsKey(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS)) {
            setAdditionalClientTypeAnnotations(readListOfStringsProperty(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS, additionalProperties));
        }
        writePropertyBack(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS, additionalClientTypeAnnotations);

        var clientId = additionalProperties.get(CLIENT_ID);
        if (clientId != null) {
            this.clientId = clientId.toString();
        }
        if (this.clientId != null) {
            writePropertyBack(OPT_CONFIGURE_CLIENT_ID, true);
            writePropertyBack(CLIENT_ID, this.clientId);
        }

        if (additionalProperties.containsKey(OPT_CLIENT_PATH)) {
            clientPath = convertPropertyToBoolean(OPT_CLIENT_PATH);
        }
        writePropertyBack(OPT_CLIENT_PATH, clientPath);

        var basePathSeparator = additionalProperties.get(BASE_PATH_SEPARATOR);
        if (basePathSeparator != null) {
            this.basePathSeparator = basePathSeparator.toString();
        }
        writePropertyBack(BASE_PATH_SEPARATOR, this.basePathSeparator);

        // Api file
        apiTemplateFiles.clear();
        apiTemplateFiles.put("client/api.mustache", ".java");

        // Add test files
        apiTestTemplateFiles.clear();
        if (testTool.equals(OPT_TEST_JUNIT)) {
            apiTestTemplateFiles.put("client/test/api_test.mustache", ".java");
        } else if (testTool.equals(OPT_TEST_SPOCK)) {
            apiTestTemplateFiles.put("client/test/api_test.groovy.mustache", ".groovy");
        }

        // Add documentation files
        supportingFiles.add(new SupportingFile("client/doc/README.mustache", "", "README.md").doNotOverwrite());
        supportingFiles.add(new SupportingFile("client/doc/auth.mustache", apiDocPath, "auth.md"));
        apiDocTemplateFiles.clear();
        apiDocTemplateFiles.put("client/doc/api_doc.mustache", ".md");
    }

    @Override
    public boolean isServer() {
        return false;
    }

    public void setAdditionalClientTypeAnnotations(final List additionalClientTypeAnnotations) {
        this.additionalClientTypeAnnotations = additionalClientTypeAnnotations;
    }

    public void setAuthorizationFilterPattern(final String authorizationFilterPattern) {
        this.authorizationFilterPattern = authorizationFilterPattern;
    }

    public void setClientId(final String clientId) {
        this.clientId = clientId;
    }

    public void setClientPath(boolean clientPath) {
        this.clientPath = clientPath;
    }

    public void setBasePathSeparator(final String basePathSeparator) {
        this.basePathSeparator = basePathSeparator;
    }

    public void setConfigureAuthorization(boolean configureAuthorization) {
        this.configureAuthorization = configureAuthorization;
    }

    @Override
    public JavaMicronautClientOptionsBuilder optionsBuilder() {
        return new DefaultClientOptionsBuilder();
    }

    static class DefaultClientOptionsBuilder implements JavaMicronautClientOptionsBuilder {

        private List additionalClientTypeAnnotations;
        private String authorizationFilterPattern;
        private String basePathSeparator;
        private String clientId;
        private boolean clientPath;
        private boolean useAuth;
        private boolean lombok;
        private boolean plural;
        private boolean fluxForArrays;
        private boolean generatedAnnotation = true;

        @Override
        public JavaMicronautClientOptionsBuilder withAuthorization(boolean useAuth) {
            this.useAuth = useAuth;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withAuthorizationFilterPattern(String authorizationFilterPattern) {
            this.authorizationFilterPattern = authorizationFilterPattern;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withClientId(String clientId) {
            this.clientId = clientId;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withAdditionalClientTypeAnnotations(List additionalClientTypeAnnotations) {
            this.additionalClientTypeAnnotations = additionalClientTypeAnnotations;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withBasePathSeparator(String basePathSeparator) {
            this.basePathSeparator = basePathSeparator;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withLombok(boolean lombok) {
            this.lombok = lombok;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withPlural(boolean plural) {
            this.plural = plural;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withFluxForArrays(boolean fluxForArrays) {
            this.fluxForArrays = fluxForArrays;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withGeneratedAnnotation(boolean generatedAnnotation) {
            this.generatedAnnotation = generatedAnnotation;
            return this;
        }

        @Override
        public JavaMicronautClientOptionsBuilder withClientPath(boolean clientPath) {
            this.clientPath = clientPath;
            return this;
        }

        ClientOptions build() {
            return new ClientOptions(
                additionalClientTypeAnnotations,
                authorizationFilterPattern,
                basePathSeparator,
                clientId,
                clientPath,
                useAuth,
                lombok,
                plural,
                fluxForArrays,
                generatedAnnotation
            );
        }
    }

    record ClientOptions(
        List additionalClientTypeAnnotations,
        String authorizationFilterPattern,
        String basePathSeparator,
        String clientId,
        boolean clientPath,
        boolean useAuth,
        boolean lombok,
        boolean plural,
        boolean fluxForArrays,
        boolean generatedAnnotation
    ) {
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy