Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate a Java class using Gradle for Java plugin

Tags:

java

gradle

I'd like to generate a Java class using a Gradle task for a Java project, similar to how the Android plugin creates BuildConfig.java using the buildConfig <String> notation, e.g.:

android {
    ...

    buildTypes {
        final String PROVIDER_AUTHORITY_RELEASE = "public static final String PROVIDER_AUTHORITY = \"com.example.project.ContentProvider\";\n";
        final String PROVIDER_AUTHORITY_DEBUG = "public static final String PROVIDER_AUTHORITY = \"com.example.project.debug.ContentProvider\";\n";

        debug {
            ...
            buildConfig PROVIDER_AUTHORITY_DEBUG
        }

        release {
            ...
            buildConfig PROVIDER_AUTHORITY_RELEASE
        }
    }
}

The use case is that I'm developing an open source app which requires the use of an API key and secret; I have the key and secret in gradle.properties which isn't committed to my VCS.

So far, I have this:

task generateSources {
    outputDir = file("$buildDir/../src/main/java/uk/co/ataulm/mijur/core/api")
    outputs.dir outputDir
    doFirst {
        outputDir.exists() || outputDir.mkdirs()

        String API_CLIENT_ID = "public static final String API_CLIENT_ID = \"<your imgur uk.co.ataulm.mijur.core.api client id>\";\n"
        String API_CLIENT_SECRET = "public static final String API_CLIENT_SECRET = \"<your imgur uk.co.ataulm.mijur.core.api client secret>\";\n"

        try {
            API_CLIENT_ID = "public static final String API_CLIENT_ID = \"" + apiClientId + "\";\n"
            API_CLIENT_SECRET = "public static final String API_CLIENT_SECRET = \"" + apiClientSecret + "\";\n"
        } catch (Exception e) {
            println "gradle.properties not set with apiClientId and/or apiClientSecret. API calls will not work.";
        }

        new File(outputDir, "ApiConstants.java").write("package uk.co.ataulm.mijur.core.api;\n\npublic class ApiConstants {\n" + "    " + API_CLIENT_ID + "    " + API_CLIENT_SECRET + "}")
    }
}

compileJava.source generateSources.outputs.files, sourceSets.main.java

and it works - it generates that file at the specified location. But it's very fragile; explicitly naming the package is prone to error. I'd be happy if the file is generated in some other package (e.g. at the root of the src/main/java) as long as I can access it in Java, using MyGeneratedFile.MyConstant.

Appreciate any ideas (even if they are down a different track).

like image 942
ataulm Avatar asked Nov 20 '13 18:11

ataulm


People also ask

How do you create a class in Gradle project in Java?

From inside the new project directory, run the init task using the following command in a terminal: gradle init . When prompted, select the 2: application project type and 3: Java as implementation language. Next you can choose the DSL for writing buildscripts - 1 : Groovy or 2: Kotlin .

What does Gradle Java plugin do?

The Java plugin adds the java extension to the project. This allows to configure a number of Java related properties inside a dedicated DSL block. Java version compatibility to use when compiling Java source. Default value: version of the current JVM in use.

Does Gradle work with Java?

Gradle can only run on Java version 8 or higher. Gradle still supports compiling, testing, generating Javadoc and executing applications for Java 6 and Java 7. Java 5 and below are not supported. If using Java 10+, leveraging the release flag might be an easier solution, see above.


2 Answers

I wrote a gradle plugin which aims to provide a build config like the one from android tooling gradle plugin for java/groovy projects:

https://github.com/mfuerstenau/gradle-buildconfig-plugin

It's per source set, because I needed a specific version to display for different artifacts relying on two different source sets.

just apply the plugin (gradle 2.1+)

plugins {
    'de.fuerstenau.buildconfig'
}

buildConfig {
   sourceSets {
      // this is a build config for "main" source set
      main {
         // if not defined, these are the defaults
         // packageName = project.group (not specified -> de.fuerstenau.buildconfig)
         // appName = project.name
         // version = project.version

         // custom fields con also be added
         // for example:
         // buildConfigField "String" "MYSTRING" "value"
      }
      // add more or other sourceSets like "main", be aware
      // of conflicts if you use
      // them combined
   }
}

will result in a class de.fuerstenau.buildconfig.BuildConfig (package can be configured as above):

package de.fuerstenau.buildconfig;

public final class BuildConfig
{
   private BuildConfig { }
   public final String VERSION = "<whatever-version-was-configured>";
   public final String NAME = "<whatever-appName-was-configured>";
}

Two tasks will be created and added, one to generate the class, the other to compile it, they execute before "compileJava"-task and the result is added as dependency.

like image 69
javaj Avatar answered Oct 23 '22 17:10

javaj


More elegant approach is to write a Gradle Plugin.

task javaSourceGen(type: com.somecompany.gensrc.GenerateSouce) {
  //pass appropriate parameters
}
compileJava.dependsOn(javaSourceGen)

Then in the Gradle Plugin, Any Java Source generator project can be used.

For ex: https://github.com/square/javapoet or http://codemodel.java.net/

like image 39
Pratap Koritala Avatar answered Oct 23 '22 17:10

Pratap Koritala