How to generate OpenAPI sources from gradle when building Android app
Asked Answered
M

4

10

What I'm trying to achieve

I'm trying to generate my REST API client for Android using OpenAPI Generator from the build.gradle script. That way, I wouldn't have to run the generator command line every time the specs change. Ideally, this would be generated when I build/assemble my app, and the sources would end up in the java (generated) folder, where generated sources are then accessible from the code (this is what happens with the BuildConfig.java file for example).

What I've tried so far

Following this link from their official GitHub, here's the build.gradle file I ended up with:

apply plugin: 'com.android.application'
apply plugin: 'org.openapi.generator'

...

openApiValidate {
    inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
    recommend = true
}
openApiGenerate {
    generatorName = "java"
    inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
    outputDir = "$buildDir/generated/openapi"
    groupId = "$project.group"
    id = "$project.name-openapi"
    version = "$project.version"
    apiPackage = "com.example.mypackage.api"
    invokerPackage = "com.example.mypackage.invoker"
    modelPackage = "com.example.mypackage.model"
    configOptions = [
        java8               : "true",
        dateLibrary         : "java8",
        library             : "retrofit2"
    ]
}
...

First, I've never managed to get the API generated with the build/assemble task, even when I tried adding:

compileJava.dependsOn tasks.openApiGenerate

or

assemble.dependsOn tasks.openApiGenerate

The only way I could generate the sources was by manually triggering the openApiGenerate task:

enter image description here

Then, when I do generate my sources this way, they end up in the build folder but aren't accessible from my code, and aren't visible in the java (generated) folder:

enter image description here

I then have to manually copy/paste the generated source files to my project sources in order to use the API.

Even though I'm able to work around these issues by adding manual procedures, it would be way more maintainable if the whole process was simply automatic. I was able to achieve a similar result with another tool, Protobuf. Indeed, my gradle task gets triggered every time I build the app, and the sources end up in the java (generated) folder, so I don't have to do any additional work. The task is much simpler though, so I assume the main work that I'm not able to replicate with OpenAPI Generator is handled by the Protobuf plugin itself.

Martingale answered 17/8, 2020 at 9:12 Comment(0)
E
7

I solved the issue you described like this, I'm using gradle.kts however.

See my build.gradle.kts

plugins {
    // Your other plugins
    id("org.openapi.generator") version "5.3.0"
}

openApiGenerate {
    generatorName.set("kotlin")
    inputSpec.set("$rootDir/app/src/main/openapi/my-api.yaml")
    outputDir.set("$buildDir/generated/api")
    // Your other specification
}

application {
    // Your other code
    sourceSets {
        main {
            java {
                // TODO: Set this path according to what was generated for you
                srcDir("$buildDir/generated/api/src/main/kotlin")  
            }
        }
    }
}

tasks.compileKotlin {
    dependsOn(tasks.openApiGenerate)
}

You need to build the application at least once for the IDE to detect the library (at least this is the case for me in Intellij)

Euphonic answered 3/1, 2022 at 16:59 Comment(0)
S
3

You have to specify path to the generated sources as a custom source set for your Gradle module, which is app in this case, as described here – https://developer.android.com/studio/build/build-variants#configure-sourcesets. That way Gradle will treat your sources as accessible from your code.

Something like this:

android {
  ...
  sourceSets {
    main {
      java.srcDirs = ['build/generated/openapi/src/main/java']
    }
  }
  ...
}
Sweetmeat answered 5/5, 2021 at 9:50 Comment(0)
D
1

Your build should automatically generate the open api classes , to refer the generated classes in your java project you should add the generated class path to your source directory like it was mentioned in the other answers https://developer.android.com/studio/build/build-variants#configure-sourcesets

As far as the task dependency goes , in android tasks are generated after configuration thus for gradle to recognize the task , wrap it inside afterEvaluate block like

afterEvaluate {
    tasks.compileDebugJavaWithJavac.dependsOn(tasks.openApiGenerate)
}
Decoct answered 21/6, 2022 at 7:20 Comment(0)
F
1

I had this issue, and this answer https://mcmap.net/q/239419/-error-error-nonexistentclass-kotlin-in-multi-module-dagger-project led me to a more informative error:

error: incompatible types: Object cannot be converted to Annotation
@java.lang.Object()

Taking a look at the generated files that were causing this error, noticed:

import com.squareup.moshi.Json;

After including a Moshi in the app build.gradle, the build succeeded and the generated code was accessible.

implementation("com.squareup.moshi:moshi-kotlin:1.13.0")
Forced answered 14/7, 2022 at 4:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.