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

io.sundr.swagger.language.JavaFluentCodegen Maven / Gradle / Ivy

/*
 *      Copyright 2018 The 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
 *
 *          http://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.sundr.swagger.language;

import io.sundr.Function;
import io.sundr.codegen.utils.StringUtils;
import io.swagger.codegen.v3.CliOption;
import io.swagger.codegen.v3.CodegenModel;
import io.swagger.codegen.v3.CodegenOperation;
import io.swagger.codegen.v3.CodegenProperty;
import io.swagger.codegen.v3.CodegenType;
import io.swagger.codegen.v3.CodegenParameter;
import io.swagger.codegen.v3.generators.java.JavaClientCodegen;
import io.swagger.v3.oas.models.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class JavaFluentCodegen extends JavaClientCodegen {

    private static final Logger LOGGER = LoggerFactory.getLogger(JavaFluentCodegen.class);

    public static final String GENERATE_BUILDERS = "generateBuilders";

    protected boolean generateBuilders = true;

    public JavaFluentCodegen() {
        super();
        outputFolder = "generated-code" + File.separator + "java";
        embeddedTemplateDir = templateDir = "JavaFluent";
        invokerPackage = "io.swagger.client";
        artifactId = "swagger-java-client";
        apiPackage = "io.sundr.client.api";
        modelPackage = "io.sundr.client.model";

        cliOptions.add(CliOption.newBoolean(GENERATE_BUILDERS, "Whether to generate builders for model objects."));
    }

    @Override
    public void processOpts() {
        super.processOpts();
        if (additionalProperties.containsKey(GENERATE_BUILDERS)) {
            this.setGenerateBuilders(Boolean.valueOf(additionalProperties.get(GENERATE_BUILDERS).toString()));
        }

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

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

    @Override
    public String getName() {
        return "java-fluent";
    }

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

    public void setGenerateBuilders(boolean generateBuilders) {
        this.generateBuilders = generateBuilders;
    }

    //
    // Customizations
    //
    private final Map importMappings = new HashMap<>();
    private final Map classMappings = new HashMap<>();
    private final List> knownModels = new ArrayList<>();


    @Override
    public Map postProcessModels(Map objs) {
        knownModels.add(objs);
        String pkg = (String) objs.getOrDefault("package", "");

        Object o = objs.getOrDefault("models", Collections.emptyMap());
        if (o instanceof Map) {
            refactorModel(pkg, (Map) o,objs);
        } else if (o instanceof Iterable) {
            for (Object i : (Iterable) o) {
              if  (i instanceof Map) {
                  refactorModel(pkg, (Map) i, objs);
              }
            }
        }

        return super.postProcessModels(objs);
    }

    private Map refactorModel(String pkg, Map model, Map models) {
            CodegenModel cm = (CodegenModel) model.getOrDefault("model", "");
            String importPath = (String) model.getOrDefault("importPath", "");
            String name = cm.name;
            String classname = cm.classname;
            String classFilename = cm.classFilename;

            if (generateBuilders) {
                List> imports = (List>) models.getOrDefault("imports", new ArrayList>());
                imports.add(new HashMap() {{
                    put("import", "io.sundr.builder.annotations.Buildable");
                }});

                imports.add(new HashMap() {{
                    put("import", "io.sundr.builder.annotations.Inline");
                }});

                models.put("imports", imports);
            }

            if (name.contains(".")) {

                String prefix = name.substring(0, name.lastIndexOf("."));
                String newPackage = pkg + "." + prefix;

                String newName = name.substring(name.lastIndexOf(".") + 1);
                cm.name = newName;
                cm.classname = newName;

                String newClassFilename = prefix.replaceAll("[\\.]",File.separator) + File.separator + cm.name;
                cm.classFilename = newClassFilename;

                String newImportPath = importPath.replace(pkg, newPackage).replace(classname, cm.classname);
                importMappings.put(name, newImportPath);
                classMappings.put(name, newName);

                model.put("importPath", newImportPath);
                models.put("package", newPackage);

                updateImports(knownModels, importPath, newImportPath);
                for (CodegenProperty cp : cm.vars) {
                    cp.complexType = removePackage(cp.complexType, pkg, prefix);
                    cp.baseType = removePackage(cp.baseType, pkg, prefix);
                    cp.datatypeWithEnum = removePackage(cp.datatypeWithEnum, pkg, prefix);
                    cp.defaultValue = removePackage(cp.defaultValue, pkg, prefix);
                }
            }
            models.put(GENERATE_BUILDERS, true);
            return model;
    }

    private static void updateImports(List> models, String importPath, String newImportPath) {
       for (Map objs : models) {
        Object o = objs.getOrDefault("imports", Collections.emptyMap());
        if (o instanceof Map) {
            updateImports((Map) o, importPath, newImportPath);
        } else if (o instanceof Iterable) {
            for (Object i : (Iterable) o) {
              if  (i instanceof Map) {
                  updateImports((Map) i, importPath, newImportPath);
              }
            }
        }
       }
    }

    private static void updateImports(Map imports, String importPath, String newImportPath) {
        Map copy = new HashMap<>(imports);
        for (Map.Entry e : copy.entrySet())  {
            String key = e.getKey();
            String value = e.getValue();
            if (value.equals(importPath)) {
                imports.put(key, newImportPath);
            }
        }
    }

    @Override
    public Map postProcessOperations(Map objs) {
         String pkg = (String) objs.getOrDefault("package", "");

        Object o = objs.getOrDefault("operations", Collections.emptyMap());
        if (o instanceof Map) {
            refactorOperation(pkg, (Map) o,objs);
        } else if (o instanceof Iterable) {
            for (Object i : (Iterable) o) {
              if  (i instanceof Map) {
                  refactorOperation(pkg, (Map) i, objs);
              }
            }
        }
        return objs;
    }

    private Map refactorOperation(String pkg, Map operation, Map operations) {
        String name = (String) operation.get("classname");
        if (name.contains(".")) {
            String prefix = name.substring(0, name.lastIndexOf("."));
            String newPackage = pkg + "." + prefix;
            String newName = name.substring(name.lastIndexOf(".") + 1);
            operation.put("classname", newName);
            operations.put("package", newPackage);
        }
        Object obj = operation.get("operation");
        if (obj instanceof Iterable) {
            for (Object o : (Iterable) obj) {
                if (o instanceof CodegenOperation) {
                    CodegenOperation co = (CodegenOperation) o;
                    updateModelRefs(co);
                    List> imports = (List>) operations.get("imports");
                    for (String i: co.imports) {
                        Map importMap = new HashMap<>();
                        importMap.put("import", i);
                        if (!imports.contains(importMap))  {
                            imports.add(importMap);
                        }
                    }
                }
            }
        }
        return operation;
    }

    private void updateModelRefs(CodegenOperation operation) {
        String returnType = operation.returnType;
        String returnBaseType = operation.returnBaseType;
        if (classMappings.get(returnBaseType) != null)  {
            operation.returnBaseType = classMappings.get(returnBaseType);
        }
        if (importMappings.get(returnBaseType) != null)  {
            operation.imports.add(importMappings.get(returnBaseType));
        }
        if (classMappings.get(returnType) != null)  {
            operation.returnType = classMappings.get(returnType);
        }
        if (importMappings.get(returnType) != null)  {
            operation.imports.add(importMappings.get(returnType));
        }

        for (CodegenParameter parameter : operation.allParams) {
            updateModelRefs(operation, parameter);
        }

        for (CodegenProperty property : operation.responseHeaders) {
            updateModelRefs(operation, property);
        }

        updateModelRefs(operation, operation.bodyParam);
        for (CodegenParameter parameter : operation.bodyParams) {
            updateModelRefs(operation, parameter);
        }

        for (CodegenParameter parameter : operation.formParams) {
            updateModelRefs(operation, parameter);
        }

        for (CodegenParameter parameter : operation.headerParams) {
            updateModelRefs(operation, parameter);
        }
    }

    private void updateModelRefs(CodegenOperation operation, CodegenProperty property)  {
        if  (property == null) {
            return;
        }
        String baseType = property.baseType;
        String datatype = property.datatype;
        String datatypeWithEnum = property.datatypeWithEnum;
        //baseType
        if (classMappings.get(baseType) != null)  {
            property.baseType = classMappings.get(baseType);
        }
        if (importMappings.get(baseType) != null) {
            operation.imports.add(importMappings.get(baseType));
        }
        //dataType
        if (classMappings.get(datatype) != null)  {
            property.datatype = classMappings.get(datatype);
        }
        if (importMappings.get(datatype) != null) {
            operation.imports.add(importMappings.get(datatype));
        }
        //dataTypeWithEnum
        if (classMappings.get(datatypeWithEnum) != null)  {
            property.datatypeWithEnum = classMappings.get(datatypeWithEnum);
        }
        if (importMappings.get(datatypeWithEnum) != null) {
            operation.imports.add(importMappings.get(datatypeWithEnum));
        }

    }

    private void updateModelRefs(CodegenOperation operation, CodegenParameter parameter)  {
        if  (parameter == null) {
            return;
        }
        String baseType = parameter.baseType;
        String datatype = parameter.dataType;
        String datatypeWithEnum = parameter.datatypeWithEnum;
        //baseType
        if (classMappings.get(baseType) != null)  {
            parameter.baseType = classMappings.get(baseType);
        }
        if (importMappings.get(baseType) != null) {
            operation.imports.add(importMappings.get(baseType));
        }
        //dataType
        if (classMappings.get(datatype) != null)  {
            parameter.dataType = classMappings.get(datatype);
        }
        if (importMappings.get(datatype) != null) {
            operation.imports.add(importMappings.get(datatype));
        }
        //dataTypeWithEnum
        if (classMappings.get(datatypeWithEnum) != null)  {
            parameter.datatypeWithEnum = classMappings.get(datatypeWithEnum);
        }
        if (importMappings.get(datatypeWithEnum) != null) {
            operation.imports.add(importMappings.get(datatypeWithEnum));
        }
    }


    /**
     * Add operation to group
     *
     * @param tag name of the tag
     * @param resourcePath path of the resource
     * @param operation Swagger Operation object
     * @param co Codegen Operation object
     * @param operations map of Codegen operations
     */
    @SuppressWarnings("static-method")
    public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) {
        String prefix =  co.returnBaseType != null && co.returnBaseType.contains(".")
                ? co.returnBaseType.substring(0, co.returnBaseType.lastIndexOf("."))
                : "";

        String newTag = !prefix.isEmpty()
                ? prefix + "." + tag
                : tag;

        super.addOperationToGroup(newTag, resourcePath, operation, co, operations);
    }


    private static String removePackage(String name, String basePackage, String subPackage) {
        if (name == null || name.isEmpty()) {
            return name;
        }

        if (name.contains("<") && name.contains(">")) {
            String ref = name.substring(0, name.indexOf("<"));
            String[] args = name.substring(name.indexOf("<") + 1, name.lastIndexOf(">")).split(",");
            StringBuilder sb = new StringBuilder();
            sb.append(removePackage(ref, basePackage, subPackage))
                    .append("<")
                    .append( StringUtils.join(args, new Function() {
                @Override
                public String apply(String s) {
                    return removePackage(s, basePackage, subPackage);
                }
            }, ","))
                    .append(">")
            .append(name.substring(name.lastIndexOf(">") + 1));
            return sb.toString();
        }

        if  (name.contains(".")) {
            String prefix = name.substring(0 , name.lastIndexOf("."));
            String trimmed = name.substring(name.lastIndexOf(".") + 1);
            if (prefix.equals(subPackage)) {
                return trimmed;
            } else {
               return basePackage + "." + prefix + "." + trimmed;
            }
        }
        return name;
    }

    @Override
    public String toModelName(String name) {
        return name;
    }

    @Override
    public String toModelFilename(String name) {
        return name.replaceAll(Pattern.quote("."), File.separator);
    }
    @Override
    public String toModelTestFilename(String name) {
        return super.toModelTestFilename(name).replaceAll(Pattern.quote("."), File.separator);
    }
    @Override
    public String toModelImport(String name) {
        return super.toModelImport(name);
    }

    @Override
    public String toVarName(String name) {
        return super.toVarName(name);
    }

    @Override
    public String toBooleanGetter(String name) {
        return "is" + getterAndSetterCapitalize(name);
    }


    @Override
    public String toApiDocFilename(String name) {
        return super.toApiDocFilename(name);
    }

    @Override
    public String toApiName(String name) {
        return name;
    }

    @Override
    public String toApiFilename(String name) {
        return name.replaceAll(Pattern.quote("."), File.separator);
    }

    @Override
    public String toApiTestFilename(String name) {
        return super.toApiTestFilename(name).replaceAll(Pattern.quote("."), File.separator);
    }

    @Override
    public String toApiVarName(String name) {
        return super.toApiVarName(name);
    }

    @Override
    public String toApiImport(String name) {
        return super.toApiImport(name);
    }

/*
        @Override
    public Map postProcessModels(Map objs) {
        String pkg = (String) objs.getOrDefault("package", "");

        Object o = objs.getOrDefault("models", Collections.emptyMap());
        if (o instanceof Map) {
            fixClassName((Map)o);
        } else if (o instanceof Iterable) {
            for (Object i : (Iterable) o) {
              if  (i instanceof Map) {
                  fixClassName((Map)i);
              }
            }
        }

        return super.postProcessModels(objs);
    }

    public void fixClassName(Map map) {
        CodegenModel cm = (CodegenModel) map.getOrDefault("model", "");
        String name = cm.name;
         if (name != null && !name.isEmpty() && name.contains(".")) {
             cm.name = name.substring(name.lastIndexOf(".") + 1);
             cm.classname = cm.name;
        }
    }

    @Override
    public String toModelName(String name) {
            return name;
    }

    @Override
    public String toModelImport(String name) {
        return super.toModelImport(name);
    }



    @Override
    public String toModelFilename(String name) {
        if (name == null || name.isEmpty() || !name.contains(".")) {
            return super.toModelName(name);
        }
        String prefix = name.substring(0, name.lastIndexOf("."));
        return prefix.replaceAll("[\\.]",File.separator) + File.separator + name.substring(name.lastIndexOf(".") + 1);
    }

    @Override
    public String toBooleanGetter(String name) {
        return "is" + super.toBooleanGetter(name);
    }
    */
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy