使用Gradle for Java插件生成Java类

使用Gradle for Java插件生成Java类,java,gradle,Java,Gradle,我想为Java项目使用Gradle任务生成一个Java类,类似于Android插件使用BuildConfig符号创建BuildConfig.Java,例如: android { ... buildTypes { final String PROVIDER_AUTHORITY_RELEASE = "public static final String PROVIDER_AUTHORITY = \"com.example.project.ContentProvide

我想为Java项目使用Gradle任务生成一个Java类,类似于Android插件使用
BuildConfig
符号创建
BuildConfig.Java
,例如:

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
        }
    }
}
使用案例是,我正在开发一个开源应用程序,它需要使用API密钥和密码;我在
gradle.properties
中有密钥和机密,但未提交给我的VCS

到目前为止,我有:

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
任务生成资源{
outputDir=file(“$buildDir/。/src/main/java/uk/co/ataulm/mijur/core/api”)
outputs.dir outputDir
首先{
outputDir.exists()| | outputDir.mkdirs()
String API\u CLIENT\u ID=“public static final String API\u CLIENT\u ID=\“\”;\n
String API\u CLIENT\u SECRET=“public static final String API\u CLIENT\u SECRET=\“\”;\n
试一试{
API\u CLIENT\u ID=“public static final String API\u CLIENT\u ID=\”“+apiClientId+”\”;\n
API\u CLIENT\u SECRET=“public static final String API\u CLIENT\u SECRET=\”“+apiClientSecret+”\”;\n
}捕获(例外e){
println“未使用apiClientId和/或APICLIENTSCRET.API调用设置gradle.properties将不起作用。”;
}
新文件(outputDir,“ApiConstants.java”).write(“package uk.co.ataulm.mijur.core.api;\n\n公共类ApiConstants{\n”+“”+api\u CLIENT\u ID+“”+api\u CLIENT\u SECRET+“}”)
}
}
compileJava.source generateSources.outputs.files,sourceset.main.java
它可以工作-它在指定的位置生成该文件。但它非常脆弱;显式命名包容易出错。如果文件是在其他包中生成的(例如在
src/main/java
的根目录下),我会很高兴,只要我可以使用
MyGeneratedFile.MyConstant
在java中访问它


欣赏任何想法(即使它们走的是另一条道路)。

更优雅的方法是编写Gradle插件

task javaSourceGen(type: com.somecompany.gensrc.GenerateSouce) {
  //pass appropriate parameters
}
compileJava.dependsOn(javaSourceGen)
然后在Gradle插件中,可以使用任何Java源代码生成器项目

例如:或

我编写了一个gradle插件,旨在提供一个构建配置,就像java/groovy项目的android工具gradle插件:

它是每个源集的,因为我需要一个特定的版本来显示依赖于两个不同源集的不同工件

只需应用插件(gradle 2.1+)

将导致类
de.fuerstenau.buildconfig.buildconfig
(包可以如上配置):

package de.fuerstenau.buildconfig;
公共最终类BuildConfig
{
私有BuildConfig{}
公共最终字符串版本=”;
公共最终字符串名称=”;
}

将创建并添加两个任务,一个用于生成类,另一个用于编译类,它们在“compileJava”任务之前执行,结果作为依赖项添加。

为什么不简单地使用一个带有占位符的属性文件,在构建时由实际值替换,并在运行时由您的类加载?@JBNizet在构建时被替换-就像在首次访问时一样?通过让gradle为我生成它,我可以为每个构建风格提供不同的配置。我也在考虑同样的方法,但对基于gradle的解决方案非常感兴趣。我所说的“构建时”,是指“gradle”。对我来说,在构建过程中过滤属性文件比生成Java文件要容易得多,也自然得多;如果构建脚本是版本控制的,那么实际值不应该在属性中吗?我最近将插件更新为1.1.0版。它现在支持在常规闭包中设置属性和在源集合闭包中重写。现在支持重命名生成配置。而且任务的最新计算更好,因此只有在发生变化时才会生成任务。
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
   }
}
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>";
}