gradle / intellij - shared test resource(s) - java

I have a gradle based project with 8 subprojects. Each of these has test code that relies on a folder with a number of .csv files for content. I'd rather not copy this folder into the test path of each subproject.
Is there a way to tell gradle to look for the files in a common location?
How about for IntelliJ? I tried indicating the files were a 'test resource' but haven't figured out how to get each sub-module to find them (without resorting to '../..' style notation)

I did that providing the path to the common files folder on sourceSets in the build.gradle file:
sourceSets {
test {
resources {
srcDirs = ["src/test/resources", "src/main/resources/db"]
}
}
Not sure if that's a clean way to do that, but for me it's better than copypasting the same files over multiple locations.

Related

Dependencies path difference in Gradle vs in Maven

I have a question regarding to the difference between Gradle depedencies mechanism vs Maven dependency mechanism:
My project structure is following and app is dependent on common:
project
common
conf
src
java
test
app
conf
src
java
test
and build.gradle in app is:
dependencies {
compile project(':common')
....
}
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'conf'
}
}
test {
java {
srcDir 'src/test'
}
}
}
When I use ant dist. The class paths contain /common/conf folder, which contains lots of configuration files.
When I use Gradle build. The class paths contain build/common.jar instead of /common/conf.
Is there a way I could make Gradle do the same thing as Maven does (make class paths contain /common/conf instead of build/common.jar)?
Because app will read xml configuration files under common/conf folder when I run test cases under app but app is not able to read xml from a jar file. Because right now my code is not able to handle the inputStream from Jar.
Is it using:
res.getFile()
where res is the reference to xml configuration files.
I am a newbie to both Maven and Gradle. Could someone please help? Really appreciate!
If what you're trying to achieve is have those xml files available at runtime from within the Jar, then just add your XML files to /src/main/resources.
Anything in that directory automatically gets added to the Jar file and available as classpath resources. Both Maven and Gradle use convention over configuration, where it's a convention to put classpath resources into /src/main/resources as it is to put application Java code in /src/main/java and unit test classpath resources in /src/test/resources and unit test Java code in /src/test/java.
Following Mavan/Gradle conventions will make your configuration simpler too. Unlike Ant where everything needed to be configured.
If your xml files are in common.jar (by putting the xml in common/src/main/resources, and common is on the class path for for app then you should be able to read those files by getting via class loader. E.g SomeClassFromCommon.class.getClassLoader().getResourceAsStream("somefile.xml")

Change how Gradle's build directory is organized

So, I've recently (partially) completed a Java project with Gradle. Importantly, the project uses absolute pathing to access files in my resources folder, since those files will change after the JAR is made. When I use Eclipse's "export as runnable JAR" functionality, I get something that works perfectly - putting the .jar file in my main directory lets it find everything. However, using Gradle's build function doesn't, because Gradle adds extra layers between the .jar and the resources. To demonstrate, here's my "normal" directory:
./program root directory
|_program.jar
|_resources
|_[actual resources]
And here's the directory Gradle makes:
./build folder
|_libs
| |_program.jar
|_resources
|_main
|_[actual resources]
What I want from Gradle is:
./build folder
|_program.jar
|_resources
|_[actual resources]
Yes, I could manually move the resources and program.jar around in the directory to achieve this, but that feels wrong - this is exactly what Gradle is supposed to do for me, right? I know there has to be SOME way to do it. I just don't know how. So that's why I'm asking for help - how do I do this?
To change the output of resources:
sourceSets.main.output.resourcesDir = "$buildDir/resources"
To change where the JAR file is put:
jar {
// use destinationDir for Gradle < 5.1
destinationDirectory = buildDir
}
If all your resources are meant to be external you may want to exclude them from the JAR file:
jar {
include '**/*.class'
destinationDirectory = buildDir
}
That will only include .class files from the jar task's input. You can customize this using the include and exclude options.

Gradle copy command deprecated, breaks build

In Gradle 3.x I was able to get some xml mapping files to copy into the classes directory prior to build/jar via the following block:
copy{
from 'src/main/java/com/company/mapping'
into 'build/classes/main/java/com/company/mapping'
include '**/*.xml'
}
In Gradle 4.9 this has been deprecated in favor of:
task copyMappings(type: Copy){
from 'src/main/java/com/company/mapping'
into 'build/classes/main/java/com/company/mapping'
include '**/*.xml'
}
The copyMappings task succeeds, but build/jar does not wait for copyMappings to finish. I have tried variations on build.dependsOn and doFirst{ copyMappings } doLast{ build } but nothing seems to get me the desired effect of having the copied files in place in the 'into' path prior to jar.
This is for Windows 10.
This works for me with Gradle 4.9 on Mac OS:
apply plugin: 'java'
task copyMappings(type: Copy) {
from 'src/main/java/com/company/mapping'
into 'build/classes/main/java/com/company/mapping'
include '**/*.xml'
}
jar.dependsOn copyMappings
jar.doFirst {
assert new File("${projectDir}/build/classes/main/java/com/company/mapping/abc.xml").exists()
assert new File("${projectDir}/build/classes/main/java/com/company/mapping/def.xml").exists()
}
command line is gradle clean jar
I like to model things around source sets where appropriate as doing so let's the build work more reliably with a wide range of plugins and use cases. For example, imagine you want to run an application direct from its class files and resources rather than packaging it as a JAR first. You could make sure that the "run" task depends on the copy as well, but you'd have to do that for every instance where this is a requirement.
Source sets are the ideal solution because they have the concept of a runtime classpath, which will work for packaging, instrumentation, running, testing and so on.
With that in mind, I would go for this simple declaration and get rid of the copy task:
sourceSets {
main {
resources {
srcDir "src/main/java"
include "**/*.xml"
}
}
}
The XML files will end up in a different directory from your current approach, but that shouldn't matter unless you have tasks that assume the location rather than using the source set model to get the necessary information.
Note The above include directive applies to all the resources in src/main/resources as well. So if you have properties files or text files or anything else in there, they will be excluded. The simplest solution is to add all required resource file patterns to the include directive.

How do I specify an extra folder to be on the classpath for gradle's application plugin 'run' task?

I've successfully configured my gradle build script to create a zip distribution of my application with an extra 'config' folder at the root. This folder contains (at least right now) only one properties file in use by the application, and is on the classpath for the application.
What I'm looking for now, however, is a way to do the same with the 'run' task in the application plugin. When I try to run my application this way, (for testing), my program fails to run because of a class trying to access this properties file on the root of the classpath.
A bonus would be if I could get IntelliJ or Eclipse to also add this folder to its classpath just like the other folders (src/main/java, src/main/resources, ...) so I can run and debug my code from within the IDE without invoking a gradle task. I want to try to avoid as much as possible tying this code to any one IDE, so that when anybody needs to work on the project, they just need to import the build.gradle file and have the IDE make the appropriate config files it needs.
Here is my build.gradle file:
apply plugin: 'application'
mainClassName = "MainClass"
startScripts {
// Add config folder to classpath. Using workaround at
// https://discuss.gradle.org/t/classpath-in-application-plugin-is-building-always-relative-to-app-home-lib-directory/2012
classpath += files('src/dist/config')
doLast {
def windowsScriptFile = file getWindowsScript()
def unixScriptFile = file getUnixScript()
windowsScriptFile.text = windowsScriptFile.text.replace('%APP_HOME%\\lib\\config', '%APP_HOME%\\config')
unixScriptFile.text = unixScriptFile.text.replace('$APP_HOME/lib/config', '$APP_HOME/config')
}
}
repositories {
...
}
dependencies {
...
}
Likely what needs to happen is that I need to have the /src/dist/config folder to be copied into the build directory and added to the classpath, or have its contents be copied into a folder that is already on the classpath.
I ended up taking Opal's suggestion as a hint, and came up with the following solution. I added the following to my build.gradle file:
task processConfig(type: Copy) {
from('src/main/config') {
include '**/*'
}
into 'build/config/main'
}
classes {
classes.dependsOn processConfig
}
run {
classpath += files('build/config/main')
}
Alternatively, a simpler approach would be to add a runtime dependency to my project as such:
dependencies {
...
runtime files('src/main/config')
}
I didn't end up doing it this way, however, because my distribution package ended up having .properties files in the lib folder... and I'm just picky that way.
As you can see in the docs run is a task of type JavaExec. So classpath for it can be modified. Try to add config folder to the classpath. See here.

Compile folder with .java files and Jar it

I'm trying to figure out compiling a folder with Java source files in it.
There's a folder structure (root folders are org.AppName.i18n and META-INF). Eventually I need to get a Jar with the same structure and .java's converted to .class'es. Any hints how to make it? I'm on Windows.
You can use Ant for this: http://ant.apache.org/
A build tool, like Gradle is perfect for this.
See the tutorial for java projects.
Create a build.gradle file, where you use the java plugin:
apply plugin: 'java'
You either need to move your java files to src/main/java, or specify the source folder in build.gradle, something like this:
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}
Then run 'gradle jar'

Categories

Resources