Dependencies path difference in Gradle vs in Maven - java

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")

Related

IntelliJ & Gradle : test module/sourceSet can't see main resources

Here is the simplified structure of each module of my project :
src
|- main
|- java
<My classes>
|- resources
config.properties
|- test
|- java
MainTest
|- resources
I recently updated IntelliJ to version 2019.2. As Jetbrains removed the "uncheck create separate modules per source set" (see this post), when I import a Gradle project, I end up with one module having two sub-modules : main and test.
So, in Intellij project structure, I have this :
main sub-module
test sub-module
In some class, I load the config.properties file this way :
InputStream inputStream = MyClass.class.getClassLoader().getResourceAsStream("config.properties");
But when I run MainTest.main() in IntelliJ, which at some point calls the bit of code above, the resulting InputStream is null.
I guess that the test module classpath doesn't include the main resources folder...
How can I fix that ?
When I could check the box "uncheck create separate modules per source set", I had just one module, with one classpath, and my life was easier...
Is there a way, maybe using Gradle configuration in build.gradle file, to enforce one unique module/source set ?
IntelliJ 2019.2 defaults to delegating all build and run tasks to Gradle, so it shouldn't matter how you have structured the project in IntelliJ. You could also try running your test on the command line with gradle test to see if you get the same problem (which you should).
The 'test' runtime classpath does includes the resource folder from both the 'test' and the 'main' folder. So this also shouldn't be a problem.
In the screenshot you've shown of the main modules, there are no config.properties file in the resource folder. Did you put it in the META-INF sub-folder instead? If it actually is in the root of the resource folder, try referencing it with a slash (/) in the path, e.g.:
MyClass.class.getClassLoader().getResourceAsStream("/config.properties")
^^^

gradle / intellij - shared test resource(s)

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.

What is the main-class attribute of the build.gradle file?

I was told to include this in my build.gradle file in exercism.io in order to run my test suite in Java.
jar {
manifest {
attributes 'Main-Class': 'net.petrikainulainen.gradle.HelloWorld'
}
}
What is jar? What is the attributes 'Main-Class' doing? Is it specifying where my main class exists in the build folder?
In essence, gradle seems to be doing a few things for me:
1. creating a build folder where my Javascript compiled code exists
2. running my test suite
3. fetching any dependencies that I specify in the build.gradle file.
Is this typically what a dependency manager does?
In order to run tests you don't need to add a Main-Class attribute. What you've done there is specify that when building a jar file, include the Main-Class attribute in the jars manifest, which is the class to use as the entry when running a jar file via java -jar.
In answer to your second question, Gradle isn't a dependency manager, it's a build automation tool and yes, that's typically what they do for you.

How to make a maven project recognize a file from its own directory instead of working directory?

I currently have two projects:
api-test
...
/config/config.json
...
and
ui-test
...
/config/config.json
...
In eclipse, I am adding api-test in the build path of ui-test, so that api-test is the dependency of ui-test.
However the build failed, because api-test is looking for the config.json located in api-test/config/config.json by calling:
System.getProperty("user.dir") + "/config/config.json"
which does not exist in ui-test project.
the two config.json include different contents - what would be the best solution to let each project refer to their own config.json while ui-test is referring to api-test project?
Put the files into the projects' src/main/resources directories as suggested by Maven's Standard Directory Layout. You can use relative paths to access these resources then.
See How to get file resource from Maven src/test/resources/ folder in JUnit test? For instance:
Test file existence
#Test
public void testStreamToString() {
assertNotNull("Test file missing", getClass().getResource("/sample.txt"));
...
}

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.

Categories

Resources