Gradle Jar works as intended, but Gradle Run fails - java

I recently wanted to build jars of my JavaFX project with Gradle. So I went ahead and created the wrapper in my project directory and edited my build.gradle file to the below.
apply plugin: 'java'
apply plugin: 'application'
sourceSets.main.java.srcDirs = ['/']
mainClassName = "Main"
task wrapper(type: Wrapper) {
gradleVersion = '4.8'
}
jar {
manifest {
attributes(
'Class-Path': '../',
'Main-Class': 'Main'
)
}
from('/') {
include 'images/**/*.png'
include 'images/**/*.jpg'
include 'styles/css/**/*.css'
include 'fonts/**/*.TTF'
include 'fonts/**/*.ttf'
}
}
Using this, my compiled jar works as intended. No errors. But whenver I run gradlew runI get the following error.
Caused by: java.lang.NullPointerException
at styles.java.TitleStyles.<init>(TitleStyles.java:9)
at scenes.TitleScene.<init>(TitleScene.java:34)
at scenes.SceneController.<clinit>(SceneController.java:6)
... 14 more
The code in question is
private String stylesheet = this.getClass().getResource("/styles/css/TitleStyles.css").toExternalForm();
and my project structure looking like this
Project Structure Picture
Project Structure Picture #2
Any ideas on why I'm unable to do gradlew run?

The reason you are hitting a NullpointerException when you use gradle run is because the folder structure "/styles/...." is not in the classpath
To verify this .. you can ad this line in your Main.java :
System.out.println(System.getProperty("java.class.path")) ;
and run it as both java -jar
and gradle run
and you will see the difference.
Tp solve this , use the standard gradle java folder structure :
src
- main
--- java
--- resources

It was indeed a classpath issue, but there was a few more things I had to do to resolve my problems. I had to recreate my gradle project with the following structure.
src
-main
--java
---projectCodeHere
--resources
---nonJavaFileCodeHere
I had to relocate my non-java code to resources, otherwise it wasn't copied along with the .class files.
And then I had to change my code to look a bit like thisP
private String stylesheet = getClass().getClassLoader().getResource("css/ConnectionStyles.css").toExternalForm();
Everything worked correctly after that. It seems Gradle and IntelliJ are picky about the structure of project, and I couldn't find a "clean" solution to changing classpaths, so I ended up just reorganizing my project and am I ever the happier for it. Thanks for the help!

Related

Gradle dependency between subprojects

I am trying to figure out the proper way to declare a project dependency in gradle, i have this two subprojects:
A java app
apply plugin: 'java'
sourceSets {main {java {srcDirs = ['./']}}}
dependencies{compile project(':p2')}
jar {manifest.attributes(
'Class-Path': configurations.runtime.files.collect { it.name }.join(''),
'Main-Class': 'Main'
)
}
and a java library:
apply plugin: 'java-library'
sourceSets {main {java {srcDirs = ['./']}}
}
jar {
manifest.attributes(
'Class-Path': configurations.runtime.files.collect { it.name }.join(' ')
)
}
The root project is empty and the settings just include the subprojects.
The dependencies in the p1 project only tells that p2 must be built before p1, but what about configuring p2 as a lib for p1? Right now if a run p1 i got:
Exception in thread "main" java.lang.NoClassDefFoundError: StaticClass
Gradle build is fine:
C:\...>gradle build
BUILD SUCCESSFUL in 1s
4 actionable tasks: 4 up-to-date
I have to copy and paste p2.jar to the p1.jar directory for it to run properly, how can i get gradle to do it for me?
If you're trying to pack the classes from p2 into the p1 jar, try adding this to p1's build.gradle:
jar {
from project(':p2:').sourceSets.main.output
}
This is a bit unusual, though. Normally, if you've set up a separate library project, you pack it in a separate jar and add it to the classpath of dependent projects, so it's reusable.
Setting the Class-Path on the jar's manifest won't work the way you've written it. The manifest attribute interprets each entry as a file path relative to the working dir of the JVM, but you're just giving it the name of each jar, and Gradle doesn't do any copying or moving of files when setting up configuration classpaths. It's generally not a good idea to rely on the manifest to set the classpath, as it will only work if your jars are arranged on the filesystem exactly as as the manifest expects it. If this is really what you want, then you need to set up an 'installation' directory containing all the required jars arranged as expected. The Gradle Application Plugin can probably help you to achieve this, or something equivalent, but I've never used it.
Depending on your exact needs, you should have a look at the java-library-distribution plugin or the application plugin.
The first one will package a jar and its dependencies in an archive.
The second one will do the same and allow you to configure the main jar to be executable.

How to execute a class with main method which is present in fatJar created by gradle

This is a follow up question for how to execute a built fat JAR as a gradle task?
I don't have enough points to ask my question as a comment. So I have to ask again. This question has been asked in other formats and scenarios multiple times but none of those responses helped me.
My problem:
scenario 1 : create a single jar with dependencies using gradle fatJar
scenario 2 : create a single jar with dependencies using maven assembly
Execute
java -cp sample.jar com.example.ClassA
on jar files generated in both processes.
Issue:
jar from Process 1 gives me
Error : Could not find or load main class com.example.ClassA
jar from Process 2 executes correctly.
I have extracted both jar files and both of them have the same folder structure and same files - meaning the compiled class files are present in both jar files.
I haven't specified any manifest entries in either process because I have multiple main classes and I am not trying to generate an executable jar file.
My build.gradle file looks like below:
apply plugin: 'java'
apply plugin: 'maven'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
}
sourceSets {
main{
java{
srcDirs 'src/main/java'
}
}
}
processResources {
from 'src/main/resources'
}
task compile (type: JavaCompile) {
source = sourceSets.main.java.srcDirs
include '**/*.java'
classpath = sourceSets.main.compileClasspath
destinationDir = sourceSets.main.output.classesDir
}
compile.options.compilerArgs = ["-sourcepath", "$projectDir/src/main/java"]
dependencies {
.
.
.
}
task fatJar(type:Jar) {
baseName = 'xxxxxxx'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
defaultTasks 'clean', 'compile', 'fatJar'
EDIT - 1:
I have tried relative path to the jar, absolute path to the jar and even browsing to the folder which contains the jar. No luck whatsoever.
I have tried using '/' instead of '.' in the package name. No luck there either.
I have tried using java VM arguments providing huge enough heap space. Nada.
Tried executing on powershell. Got the below error:
+ CategoryInfo : NotSpecified: (Error: Could not lo...ClassA:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
I wanted to see the contents directly so used jar -tvf path_to_jar\sample.jar . Interestingly jar command didn't execute and complained that command was not found on the classpath. I had to browse to the java installation directory and execute the command and it showed the file contents.
I am running out of ideas and options here.
Any pointers?
For some reason, no matter which config I use for fatJar, the final jar gives errors when trying to execute the main class.
Using ShadowJar task I was able to build the necessary jar and execute the main class as specified in the question.
I know this defeats the entire purpose of the question about using fatJar and executing the main class. But due to time-constraints, I had to look for alternatives.
For those who are looking for config for Shadow Jar tasks, I did it using below:
buildscript {
repositories {
mavenLocal()
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3'
}
}
}
apply plugin: 'com.github.johnrengelman.shadow'
and finally to execute the task, I used
gradle shadowJar
It looks like your execution command is not valid. After building your project with:
./gradlew clean fatJar
you should use following command to execute your program:
java -cp build/libs/xxxxxxx.jar com.example.ClassA
Parameter -cp build/libs/xxxxxxx.jar sets the classpath for JVM that is about to start and it has to point to the existing JAR file (you can use relative or absolute path to this file).
Take a look at following screencast I've recorded a few minutes ago:
You can see that if I change execution command to:
java -cp xxxxxxx.jar com.example.ClassA
I got exactly the same error as yours:
Error: Could not find or load main class com.example.ClassA
Here you can find a simple Gradle project I used to play around with your build.gradle file example. I've added a single dependency to prove that fatJar builds a JAR with dependencies and I've added to classes with public static void main(String[] args) to prove that you can pick any main class from command line. I hope it helps.

Access file in JUnit test in Gradle environment

Right now I have got a Java library which has a test class. In that class I want to access some files located on my hard disk.
The build.gradle looks like this:
apply plugin: 'java'
dependencies {
testCompile 'junit:junit:4.11'
}
My file is under java_lib/src/test/assets/file.xml and the Java class is under java_lib/src/test/java/<package_name>.java
Therefore I execute
final InputStream resourceAsStream = this.getClass().getResourceAsStream("assets/file.xml");
Unfortunately I get null back. What am I doing wrong?
To get thing rolling you need to add the following to the gradle file:
task copyTestResources(type: Copy) {
from "${projectDir}/src/test/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyTestResources
What it basically does is copying all the files in the src/test/resource directory to build/classes/test, since this.getClass().getClassLoader().getResourceAsStream(".") points to build/classes/test.
The issue is already known to Google and they want to fix it in Android Studio 1.2 (since they need IntelliJ14 for that and it seems like it will be included in Android Studio 1.2)
Try placing file.xml under src/test/resources and use this.getClass().getResourceAsStream("file.xml") (without the folder prefix)
The problem appears to be that the assets folder is not part of the test runtime classpath, hence this.getClass().getResourceAsStream("assets/file.xml") wouldn't be able to resolve the path as you expected.
By default, the test resources folder in a Gradle java project is src/test/resources (same as a Maven java project). You can override it to assets folder if you wish by adding this in the project's build.gradle file:
sourceSets.test {
resources.srcDirs = ["src/test/assets"]
}
In build.gradle, add this :
sourceSets.test {
resources.srcDirs = ["src/test"]
}
In your code, access your resource like this :
getClass().getClassLoader().getResourceAsStream("assets/file.xml"));
Works for me.
Thanks for pointing out the Google issue I've been looking all day for this...
In "Android Studio 1.1 RC 1" (gradle build tool 1.1.0-rc1) there is no need to add the work around to the gradle file, but your you have to execute the test from the gradle task menu (or command prompt)!
This worked for me (3 years later, gradle 4.10)
subprojects {
junitPlatformTest.dependsOn processTestResources
}

gradle: Skipping task ':compileJava' as it has no source files

i try gradle -d compileJava in my try project, and gradle raise "Skipping task ':compileJava' as it has no source files.". the worse thing is that i can't see anything created in build/. i create this project only with running gradle init and creating a "src/Ex.java".
my question is:
How to load default "compileJava" or define my "compileJava" to fix this warning.
By default, Java source files need to go into src/main/java (or src/test/java for test sources). Either adapt your directory structure accordingly, or reconfigure the source directory as follows:
sourceSets {
main {
java {
srcDirs = ["src"]
}
}
}
You can also change gradle version to 4.8 in
gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
then do:
./gradlew build

Unable to find main class :bootRepackage

I got a problem with my gradle build. I use the standard proposed by the Spring Website (https://spring.io/guides/gs/rest-service/), but when I try to use gradle build, I got this error :
It doesnt work for this gradle, but when I use another one (that I took when I was at school) it work perfectly.
There are two possibilities
Your source directory is not in the right location (use the sourceSets directive to fix this. your source directory should resemble something like src/main/java/your/package)
Add this to indicate where your main class is
springBoot {
mainClass = "hello.FileUploader"
}
I am pretty sure it is 1.
I also have this problem, Here I solved the problem:
use org.springframework.boot:spring-boot-starter instead of org.springframework.boot:spring-boot-starter-web, if your project is only an module that will be used in other project.
Or Set the main class in gradle:
mainClassName = 'your.package.MainClass'
Or Just disable the bootRepackage
bootRepackage {
enabled = false
}
There is no main method in your project (otherwise the plugin would find one). A main method has a very specific signature, so check that you have public static void main(String[] args).
If the main class is not defined in the current project which the build.gradle file belongs to, but you want to launch it for some purpose, like sprint integration test. Do it like this:
Adding
bootRepackage {
mainClass = 'your.app.package.Application'
}
in build.gradle (after the line apply plugin: 'spring-boot', because the plugin needs to be loaded) fix the problem.
I know this is a very old post. But I came across this issue while trying to build my first spring- boot application (https://spring.io/guides/gs/spring-boot/#scratch).
So the location of the pom.xml, mentioned in the tutorial is incorrect. You need to place it outside your src folder.
So here is the final directory structure -
/workspace/src/main/java/hello/HelloController.java
/workspace/src/main/java/hello/Application.java
/workspace/pom.xml
I solved it by specifying the encoding. Probably it's because I wrote the code in an IDE.
java -Dfile.encoding=UTF-8 -jar build <filename>.jar
This happened to me as well.
I was confused by the location of build.gradle file: I thought it should be located in src/main/java/hello, because it is mentioned right after the instruction to create this sub-directory structure.
It should be placed in the root folder containing src folder. Once I did that and called "gradle build" from the root folder and not "./gradlew build" as the guide instructs, build was successful.
I did not perform the standard installation for gradle, just downloaded the binaries, maybe this is the reason that "./gradlew build" failed for me.

Categories