5

I have the following class in src/main/java/com/company/project/Config.java:

public class Config {

  public static final boolean DEBUG = true;

  ...
}

so that in some other class I can do the following, knowing that the java compiler will strip the if() statement if it evaluates to false:

import static com.company.project.Config.DEBUG

if (DEBUG) {
  client.sendMessage("something");

  log.debug("something");
}

In Gradle, what is the best way to filter and change DEBUG value in Config.java at compile time without modifying the original file?

So far I'm thinking:

  1. Create a task updateDebug(type:Copy) that filters DEBUG and copies Config.java to a temporary location
  2. Exclude from sourceSets the original Config.java file and include the temporary one
  3. Make compileJava.dependsOn updateDebug

Is the above possible? Is there a better way?

Mirco
  • 71
  • 7
  • 1
    there is no guarantee that the compiler will strip the always false if branch. – Zielu Mar 22 '15 at 14:37
  • http://stackoverflow.com/questions/17197636/is-it-possible-to-declare-a-variable-in-gradle-usable-in-java? – Marco Acierno Mar 22 '15 at 14:38
  • @Zielu http://stackoverflow.com/questions/1344270/java-preprocessor – Mirco Mar 22 '15 at 14:59
  • @Marco thank you for the link, however for the compiler to be able to remove the if() statement the DEBUG variable must be initialized at compile time and not at run time – Mirco Mar 22 '15 at 14:59
  • If you're using any kind of standard logger, why do you care that debug messages are logged? If you don't want them to show up, configure the log level of the application to be greater than DEBUG (likely "info"). – Makoto Mar 22 '15 at 17:28
  • @Makoto it's not just logging; inside a if(DEBUG) statement I might also need to run some extra code that I want to disappear in production mode. – Mirco Mar 22 '15 at 19:06

1 Answers1

2

To answer my own question, given the class src/main/java/com/company/project/Config.java:

public class Config {

  public static final boolean DEBUG = true;

  ...
}

this is the Gradle code I came up with:

//
// Command line: gradle war -Production
//
boolean production = hasProperty("roduction");

//
// Import java regex
//
import java.util.regex.*

//
// Change Config.java DEBUG value based on the build type
//
String filterDebugHelper(String line) {
  Pattern pattern = Pattern.compile("(boolean\\s+DEBUG\\s*=\\s*)(true|false)(\\s*;)");
  Matcher matcher = pattern.matcher(line);
  if (matcher.find()) {
    line = matcher.replaceFirst("\$1"+(production? "false": "true")+"\$3");
  }

  return (line);
}

//
// Filter Config.java and inizialize 'DEBUG' according to the current build type
//
task filterDebug(type: Copy) {
  from ("${projectDir}/src/main/java/com/company/project") {
    include "Config.java"

    filter { String line -> filterDebugHelper(line) }
  }
  into "${buildDir}/tmp/filterJava"
}

//
// Remove from compilation the original Config.java and add the filtered one
//
sourceSets {
  main {
    java {
      srcDirs ("${projectDir}/src/main/java", "${buildDir}/tmp/filterJava")
      exclude ("com/company/project/Config.java")
    }

    resources {
    }
  }
}

//
// Execute 'filterDebug' task before compiling 
//
compileJava {
  dependsOn filterDebug
}

It's admittedly a little hacky but it works, and it gives me the most efficient solution while still controlling development/production builds from a single point of entry (build.gradle).

Mirco
  • 71
  • 7