Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JAVA] 3.0.0-rc0 Cannot Use Custom Templates #7721

Closed
DarkWingDuckWing opened this issue Feb 25, 2018 · 1 comment · Fixed by swagger-api/swagger-codegen-generators#62
Closed

Comments

@DarkWingDuckWing
Copy link
Contributor

DarkWingDuckWing commented Feb 25, 2018

Description

Hey all, I love your work.
I've upgraded from 2.3.1 and have found that my custom mustache files are no longer found when running swagger-codegen. I have dug in a bit and have found that the templateDir variable is overwritten after being properly set from my gradle task. What's worse, is that I successfully was able to override a method on JavaClientCodegen to set templateDir properly again, and when it came time for processing the template the template was not found for some mysterious reason.

Swagger-codegen version

3.0.0-rc0

Relevant code

I ended up cloning the repositories and building locally to be able to run with the latest code since I was having the issue on 3.0.0-rc0 and found This issue over on the swagger-codegen-generators GitHub project that made it seem possible it was already resolved on the SNAPSHOT.

Gradle buildSrc:

apply plugin: 'java'

repositories {
    mavenLocal()
    jcenter()
}

dependencies {
    compile group: 'io.swagger', name: 'swagger-codegen-cli', version: '3.0.0-SNAPSHOT'
//    compile group: 'io.swagger', name: 'swagger-codegen-generators', version: '1.0.0-SNAPSHOT'
// I tried both of the above
}

build.gradle:

import io.swagger.codegen.config.CodegenConfigurator
import io.swagger.codegen.DefaultGenerator

apply plugin: 'java'
apply plugin: 'maven'

buildscript {
    repositories {
        mavenLocal()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath('io.swagger:swagger-codegen:3.0.0-SNAPSHOT')
    }
}

def swaggerInput = "src/main/resources/swaggerdoc.json"
def swaggerOutputDir = file('build/swagger')
task ('swagger') {
    inputs.file(swaggerInput)
    outputs.dir(swaggerOutputDir)
    doLast {
        def config = new CodegenConfigurator()
        config.setInputSpec(swaggerInput)
        config.setOutputDir(swaggerOutputDir.path)
        config.setLang('com.job.qa.automation.lib.codegen.MyJavaCodegen')
        config.setTemplateDir('src/main/resources/templates')
        config.setAdditionalProperties([
                'invokerPackage'   : 'com.job.api.util',
                'modelPackage'     : 'com.job.api.dto',
                'apiPackage'       : 'com.job.api.controllers',
                'dateLibrary'      : 'java8',
        ])
        new DefaultGenerator().opts(config.toClientOptInput()).generate()
    }
}

MyJavaCodegen. I should note that I've already successfully used a custom codegen class such as this, but stripped it down to just focus on this template problem:

package com.job.qa.automation.lib.codegen;

import io.swagger.codegen.languages.java.JavaClientCodegen;

public class MyJavaCodegen extends JavaClientCodegen {

  public MyJavaCodegen() {
    super();
  }

  @Override
  public void processOpts() {
    super.processOpts();
    templateDir = "src/main/resources/templates";

    modelTemplateFiles.remove("model.mustache");
    modelTemplateFiles.put("myDto.mustache", ".java");
  }
}

Relevant JavaClientCodegen code. The templateVersion code was added not too far back, but even before it was added we still had the situation where the templateDir set in the super.processOpts() call is always overwritten just after when also setting embeddedTemplateDir:

    @Override
    public void processOpts() {
        super.processOpts();
        String templateVersion = getTemplateVersion();
        if (StringUtils.isNotBlank(templateVersion)) {
            embeddedTemplateDir = templateDir = String.format("%s/Java", templateVersion);
        } else {
            embeddedTemplateDir = templateDir = String.format("%s/Java", DEFAULT_TEMPLATE_VERSION);
        }

But again, this is only half of the problem, even with MyJavaCodegen salvaging the templateDir value, we run into a problem again.

Caused by: java.io.FileNotFoundException: /src/main/resources/templates/myDto.mustache
        at com.github.jknack.handlebars.io.URLTemplateLoader.sourceAt(URLTemplateLoader.java:70)
        at com.github.jknack.handlebars.Handlebars.compile(Handlebars.java:357)
        at com.github.jknack.handlebars.Handlebars.compile(Handlebars.java:343)
        at io.swagger.codegen.DefaultGenerator.getHandlebars(DefaultGenerator.java:1019)
        at io.swagger.codegen.DefaultGenerator.processTemplateToFile(DefaultGenerator.java:742)
        at io.swagger.codegen.DefaultGenerator.generateModels(DefaultGenerator.java:394)
        ... 82 more

Okay, it looks like we should change

    templateDir = "src/main/resources/templates";

to

    templateDir = new File("src/main/resources/templates").getAbsolutePath();

This yields:

Caused by: java.io.FileNotFoundException: //Users/admin/checkout/project/src/main/resources/templates/myDto.mustache
        at com.github.jknack.handlebars.io.URLTemplateLoader.sourceAt(URLTemplateLoader.java:70)
        at com.github.jknack.handlebars.Handlebars.compile(Handlebars.java:357)
        at com.github.jknack.handlebars.Handlebars.compile(Handlebars.java:343)
        at io.swagger.codegen.DefaultGenerator.getHandlebars(DefaultGenerator.java:1019)
        at io.swagger.codegen.DefaultGenerator.processTemplateToFile(DefaultGenerator.java:742)
        at io.swagger.codegen.DefaultGenerator.generateModels(DefaultGenerator.java:394)
        ... 82 more

That path starts //Users... interesting. I debugged the program and set a breakpoint to change the path to not include the double forward slash, but it still failed with the same exception.

What happens if I don't try to use my custom mustache files, but still try to set the templateDir? Well, if I leave the modelTemplateFiles HashMap alone in MyJavaCodegen I get the following exception:

Caused by: java.io.FileNotFoundException: /src/main/resources/templates/v2/Java/model.mustache
        at com.github.jknack.handlebars.io.URLTemplateLoader.sourceAt(URLTemplateLoader.java:70)
        at com.github.jknack.handlebars.Handlebars.compile(Handlebars.java:357)
        at com.github.jknack.handlebars.Handlebars.compile(Handlebars.java:343)
        at io.swagger.codegen.DefaultGenerator.getHandlebars(DefaultGenerator.java:1019)
        at io.swagger.codegen.DefaultGenerator.processTemplateToFile(DefaultGenerator.java:742)
        at io.swagger.codegen.DefaultGenerator.generateModels(DefaultGenerator.java:394)

I wasn't able to make any sense of the the problem within sourceAt(URLTemplateLoader.java:70).
Its source is the following:

  @Override
  public TemplateSource sourceAt(final String uri) throws IOException {
    notEmpty(uri, "The uri is required.");
    String location = resolve(normalize(uri));
    URL resource = getResource(location);
    if (resource == null) {
      throw new FileNotFoundException(location);
    }
    return new URLTemplateSource(location, resource);
  }

And we are failing at getResource(location which is the following:

  @Override
  protected URL getResource(final String location) {
    return  getClass().getResource(location);
  }

I tried other location strings for files elsewhere on my filesystem, and in the top level of my resources directory, such as simply "swaggerdoc.json", but everything failed the same way, returning null.

Steps to reproduce

./gradlew swagger after the setup I've described above.

Related issues/PRs

Similar issue that happened July 2017
#4627

Suggest a fix/enhancement

Part of the solution is likely to remove the setting of templateDir from JavaClientCodegen#processOpts. If there is for some reason a need for templateDir to either not be null or to be a valid directory, we can take care of that in the getter in DefaultCodegenConfig, just like embeddedTemplateDir is as follows:

    public String embeddedTemplateDir() {
        if (embeddedTemplateDir != null) {
            return embeddedTemplateDir;
        } else {
            return templateDir;
        }
    }

templateDir could be as follows:

    public String templateDir() {
        if (templateDir != null) {
            return templateDir;
        } else {
            return embeddedTemplateDir;
        }
    }

Or this can be taken care of in JavaClientCodegen#processOpts by making the beginning of the method the following:

    @Override
    public void processOpts() {
        super.processOpts();
        String templateVersion = getTemplateVersion();
        if (StringUtils.isNotBlank(templateVersion)) {
            embeddedTemplateDir = String.format("%s/Java", templateVersion);
        } else {
            embeddedTemplateDir = String.format("%s/Java", DEFAULT_TEMPLATE_VERSION);
        }
        if (templateDir == null || !new File(templateDir).exists()) {
            templateDir = embeddedTemplateDir;
        }
@HugoMario HugoMario self-assigned this Feb 25, 2018
@DarkWingDuckWing DarkWingDuckWing changed the title [JAVA] 3.0.0-rc0 Cannot Use Custom Templates [JAVA] 2.4.0/3.0.0-rc0 Cannot Use Custom Templates Feb 25, 2018
@DarkWingDuckWing DarkWingDuckWing changed the title [JAVA] 2.4.0/3.0.0-rc0 Cannot Use Custom Templates [JAVA] 3.0.0-rc0 Cannot Use Custom Templates Feb 25, 2018
@jmini
Copy link
Contributor

jmini commented Feb 28, 2018

This is interesting, I have referenced the block required in JavaClientCodegen#processOpts here: https://github.com/swagger-api/swagger-codegen/wiki/Swagger-Codegen-migration-(swagger-codegen-generators-repository)

If the last solution is adopted (where each codegen class needs to be modified), the wiki-page needs to be corrected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants