OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.48k stars 6.5k forks source link

How to use a custom generator with gradle plugin? #6190

Open jaysson opened 4 years ago

jaysson commented 4 years ago
Description

I am new to gradle & openAPI. I generated a custom openapi generator and put it in a multi project setup. How do I use this generator in my task?

openapi-generator version

Latest

Command line used for generation

I have a two projects, api and my-generator. I have a gradle task in api as below:

dependencies {
    ....
    implementation(project(":my-generator"))
}

tasks.register<org.openapitools.generator.gradle.plugin.tasks.GenerateTask>("generateApiControllers") {
    generatorName.value("my-generator")

It throws ERROR: Unable to load class 'my-generator'.

How do I make openapi-generator recognise my-generator?

vitaly-magyari commented 4 years ago

Same issue, gradle plugin readme lacks Custom Generator section, unlike maven one. Seems like currently unsupported.

I'd try to implement it myself, if somebody gives me guidance.

I see it must be present in the output of Generators task But I'm not sure how to properly implement external generator dependency handling in the plugin.

brisssou commented 4 years ago

here is how we ended up doing it:

dependencies {
    openAPIGenerator "org.openapitools:openapi-generator-cli:4.3.1"
    openAPIGenerator(project(":my-generator"))
}
task generateClientSource(type: JavaExec) {
    classpath = configurations.openAPIGenerator
    main = "org.openapitools.codegen.OpenAPIGenerator"args([
            'generate',
            '-i',
            swagger_file,
            '-g',
            'my-generator',
            '-o',
            generatedSourceDirectory
    ])
}

I'm no Gradle expert either, but here is what I've been told: The GenerateTask code package also contain the generator code. This classpath of the task is evaluated during the configuration phase of the gradle build, and you cannot go back and update the build env. The classpath of the task execution is the gradle execution one, the task is not spawning a new jvm with a new class path.

Hope this helps!

OrdinaryNick commented 4 years ago

The solution is simple if you know how Gradle plugins work. Here are steps how to do it:

  1. You need to add your custom generator class to the classpath of the plugin. But, you can not use there any module of the Gradle project, in which you want to use the generator plugin, because Gradle plugins are applied before the whole compilation of the project and also before dependencies are resolved. So, you must use the already compiled jar file. For example, create a new Gradle project where you place custom generator code and publish it to maven local repository (https://stackoverflow.com/questions/42765113/how-to-publish-source-into-local-maven-repository-with-gradle). Then you can add it to plugins classpath like this:

    buildscript {
      repositories {
          mavenLocal()
          mavenCentral()
      }
      dependencies {
          classpath "org.openapitools:openapi-generator:4.3.0"
          classpath "some.custom.openapi:generator:0.0.1"
      }
    }
  2. Openapi generator use Java service loader to load generators (https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html). So, in your custom generator project create file org.openapitools.codegen.CodegenConfig with content

    some.custom.openapi.CustomJavaCodegen

    (Here must be the name of the custom generator class) and place it to folder src/main/resources/META-INF/services/.

  3. In your custom generator class override method getName with your generator name, which you will use in the configuration of openApiGenerator in the Gradle file.

I get this working with these steps. If I forget something to write it here, comment, and I will try to fill missing information.

msanssouci commented 3 years ago

@OrdinaryNick I am trying to use your suggestion. I am able to run the GeneratorsTask and see that my custom generator is available.

However, when i attempt to run my custom generator, I see a class not found exception:

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.openapitools.codegen.utils.ModelUtils
        at org.openapitools.codegen.config.CodegenConfigurator.toContext(CodegenConfigurator.java:512)
        at org.openapitools.codegen.config.CodegenConfigurator.toClientOptInput(CodegenConfigurator.java:568)

This is strange because this class is in the openapi-generator library so i am not sure why the class is not found.

OrdinaryNick commented 3 years ago

@msanssouci I am so sorry for very late reply. If you still not figured out solution, I am afraid of that I can not help you with that. Because there are to many options which can cause this. One of them can be: bad package of class, typo in class name in file org.openapitools.codegen.CodegenConfig, missing class in jar file, etc. If you still need help, you must provide me more information, like project structure, file content of build.gradle of plugin, content of file org.openapitools.codegen.CodegenConfig, etc. But I think, that this is not part of this issue.

jontunjon commented 3 years ago

@msanssouci I experienced the same error (i.e. java.lang.NoClassDefFoundError: Could not initialize class org.openapitools.codegen.utils.ModelUtils) recently. I'm also in a multi-project setup and the root cause was that we had also declared the gradle-swagger-generator-plugin plugin. Once I removed that plugin the build was successful.

mklueh commented 2 years ago

I'm facing the error > Could not initialize class org.openapitools.codegen.utils.ModelUtils using Quarkus and OpenAPI Tools 6.0.1 and JDK 17 This project is impossible to use for me

tokuhirom commented 1 year ago

https://github.com/OpenAPITools/openapi-generator/issues/6190#issuecomment-694186178 is mostly perfect solution for me. And one more thing, I put my own custom generator inbuildSrc. https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources

.
├── build.gradle.kts
├── buildSrc
│   └── src
│       └── main
│           ├── java
│           │   └── my
│           │       └── own
│           │           └── Generator.java
│           └── resources
│               └── META-INF
│                   └── services
│                       └── org.openapitools.codegen.CodegenConfig
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts

In this form, I can manage my own generator in the same gradle project.

slifty commented 8 months ago

#6190 (comment) is mostly perfect solution for me. And one more thing, I put my own custom generator inbuildSrc. https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources

@tokuhirom When I attempt this I'm getting compilation errors along the lines of package io.swagger.codegen.v3.generators does not exist <-- which is just to say I must not have my depencencies properly defined in my build.gradle

Would you happen to have a working example on github that includes file contents?

Swilvan commented 3 months ago

https://github.com/OpenAPITools/openapi-generator/issues/6190#issuecomment-1487839447 from @tokuhirom was solved this for me. @slifty I think you may be missing a build.gradle.kts file in buildSrc where you define the correct dependencies?