Search code examples
javagradlebuildresources

How to exclude resources from the JAR in Gradle and also run via IntelliJ


I recently started work on a 7+ year old project which uses Ant/Ivy for dependency & build management. I'm tasked with converting this to Gradle but the structure is a bit unconventional:

|- projectRoot
  |- folderA
  |- folderB
  |- projectX
    |- conf
    | |- file1.txt
    |
    |- core
    |  |- src
    |  | |- App.java
    |  |
    |  |- test
    |    |- AppTest.java
    |
    |- res
    | |- file2.txt
    |
    |- ivybuild.xml
    |- ivysettings.xml

The Ivy build process is fairly straight forward, the resulting dist folder looks like this:

|- dist
  |- proj.jar
  |- lib
  |  |- dep1.jar
  |  |- dep2.jar
  |
  |- conf
  |  |- file1.txt
  |- res
     |- file2.txt

No resources are build in to the resulting JAR as some configurations are applied from a separate repository during deployment, thus the resources must stay external to the JAR.

I'm struggling to find a way to achieve this while also letting the IDE (Intellij IDEA) successfully locate the resources during debugging and running tests.

sourceSets {
    main {
        java {
            srcDir 'core/src'
        }
        resources {
            srcDir 'conf'
            srcDir 'res'
        }
    }
    test {
        java {
            srcDir 'core/test'
        }
    }
}
processResources {
    from 'conf' into 'lib/conf'
    from 'res' into 'lib/res'
}
startScripts {
    classpath += files('conf')
    classpath += files('res')
}

With the above I'm able to run/test the project successfully as all files from 'conf' and 'res' are copied into 'build/resources/main' which allows both debugging and tests to locate them. It copies both resource directories to the output lib folder and these are added to the classpath in the run script.

The above works except that the resources are still being copied into the built JAR. These override the external folder configurations so it will not do.

jar {
    processResources {
        exclude("*")
    }
}

If I now run just assemble then the built project is exactly how I want it, however the IDE now cannot run the debugger or tests successfully as it cannot locate the files missing under build/resources/main

I have also tried the idea plugin to set the resource paths but to no avail.

Is there a way?


Solution

  • Excluding Resources from the JAR with Gradle

    Example build.gradle

    plugins {
        id 'java'
        id 'application'
    }
    
    // Project specifics
    version '1.0-SNAPSHOT'
    group 'com.example'
    
    sourceCompatibility = 1.8
    project.mainClassName = "core.ExampleApp"
    
    dependencies {
        testCompile 'junit:junit:4.12'
    }
    
    // Define the project source paths
    sourceSets {
        main.java {
            srcDir 'core/src'
        }
        test.java {
            srcDir 'core/test'
        }
    }
    
    // Exclude all resources from the jar
    jar {
        processResources.exclude('*')
    }
    
    // Allows the 'test' task to see the directories on the classpath
    test {
        classpath += files('conf')
        classpath += files('res')
    }
    
    // Allows the 'run' task to see the directories on the classpath
    run {
        classpath += files('conf')
        classpath += files('res')
    }
    
    // Adds the directories to classpath in the start scripts
    // They will have '$APP_DIR/lib/' prepended so they need to be copied into 'dist/lib/'
    startScripts {
        run {
            classpath += files('conf')
            classpath += files('res')
        }
    }
    
    // Copy 'conf' and 'res' into the 'dist/lib' directory
    distributions {
        main {
            contents {
                from('conf').into("lib/conf")
                from('res').into("lib/res")
            }
        }
    }
    
    
    • Resources are found during gradle run
    • Resources are found during gradle test
    • Built JAR does not contain the resources
    • Resources copied into example.zip/lib/conf & .../lib/res
    • Resource content are added to the classpath in the generated build scripts
    • Running tests via IntelliJ UI does work (right click -> run tests e.g.)

    BUT:

    • Running via IntelliJ UI does not work (right click -> run main() e.g.)

    Resolution:

    • The IntelliJ Gradle Plugin allows right click -> run and right click -> debug
    • The above adds a configuration to IntelliJ run panel as a decent substitute