dependencies {
compile 'org.slf4j:slf4j-api:1.7.13'
compile group: 'org.apache.commons', name: 'commons-math3' , version: '+'
testCompile 'junit:junit:4.12'
}
Even if I add this, when I run gradle build, it works, and codes with commons-math3 can be compiled. But when I run a jar file in build/,
it says Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/math3/complex/Complex
But the official Gradle site says, the resource in 'compile' will also be included in 'runtime' dependency. and I also tried adding the commons-math to runtime. but it does not work.
Maybe this is my misunderstood of the dependency system.
How can I include external library from maven repository into a jar file made by the Gradle.
What you are looking for is either the distribution zips produced by the application plugin or the shadow jar (also called fat jar) produced by the shadowJar plugin:
The distribution zip (application plugin)
About the distribution zip
The distribution zips look like this:
my-app-0.2.0.zip
├──bin
│ ├──my-app
│ └──my-app.bat
└──lib
├──my-app-0.2.0.jar
├──slf4j-api.1.7.13.jar
└──commons-math3-3.6.jar
You can then run your application with its dependencies by unzipping what has been produced in build/distributions/ and running either my-app.bat (on windows) or ./my-app (on linux or OS X)
Building a distribution zip
Here is a sample gradle build file for making a distribution zip:
build.gradle
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'org.myapp.Main'
repositories { jcenter() }
dependencies {
compile 'org.slf4j:slf4j-api:1.7.13'
compile 'org.apache.commons:commons-math3:3.6'
testCompile 'junit:junit:4.12'
}
Can be run with gradle distributionZip or gradle distributionTar. To just run the application, use gradle run.
The shadow jar
About the shadow jar
The shadow jar is one giant jar file that is a combination of your program and its libraries, packed together into one file. You will get a file that is self-contained and can be run by a double-click on most systems (e.g. on Windows that works, on Xubuntu it can be run by right-clicking and selecting 'Run with Oracle Java 8 Runtime', etc...).
Building a distribution zip
Here is, again, a sample build.gradle file:
apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'
mainClassName = 'org.myapp.Main'
jar {
manifest {
attributes('Main-Class': mainClassName)
}
}
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.2'
}
}
repositories { jcenter() }
dependencies {
compile 'org.slf4j:slf4j-api:1.7.13'
compile 'org.apache.commons:commons-math3:3.6'
testCompile 'junit:junit:4.12'
}
Run it with gradle shadowJar - Your jar with packed dependencies will be in build/libs and it will be named my-app-x.x.x-all.jar.
Gradle is first of all a build tool (just like maven, btw).
Its "responisiblity" starts when you feed it a source file and ends when you get your artifact (in your case its a jar).
Now when you're going to actually run your application there is a plethora of different options here.
If you just run java -jar <your_jar> you are responsible by yourself to construct the classpath.
If you run it with some kind of external runner, you should read the documentation of it and supply it a classpath.
Hope this helps
Related
I basically want to do something simple - or atleast i think it should be pretty simple.
My goal is to create an Intellij gradle project, add some dependencies to the module using gradle and add some java source code to it.
Then I just want to have an option to somehow compile the whole thing into 1 jar, containing all grade dependencies and being able to execute using "java -jar"
However it turned out that this is not as easy is i had thought.
I just created a new gradle project from intellij and added a Main class.
I´ll give you an overview over my files:
settings.gradle:
rootProject.name = 'gradleTestNewJar'
build.gradle:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
sourceCompatibility = 1.6
version = '1.0'
repositories {
mavenCentral()
}
mainClassName = "com.randomPackage.StarterClass"
dependencies {
compile 'org.seleniumhq.selenium:selenium-java:2.46.0'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
main class:
package com.randomPackage;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
public class StarterClass {
public static void main(String[] args){
System.out.println("test");
WebDriver driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_38);
driver.quit();
}
}
The main method of "MyStart" is executed when running from Intellij via debug.
So it works, when all dependencies get loaded correctly.
NOTE: I use Intellij Community Edition if this makes any difference.
What i tried:
1. I tried to just use "gradlew clean build".
This created a jar, but without libs.
But I didn´t expect it to be as easy as this.
2. I tried to build an artifact of the module as suggested here:
http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/
I tried it with extracted and not extracted dependencies.
In both cases the dependencies were added into the jar, but they were added to the root of the jar.
When i tried to run the jar file via "java -jar", it complained:
"Exception in thread "main" java.lang.NoClassDefFoundError: org/openqa/selenium/WebDriver
..."
OK, so it couldn´t load the dependencies.
NOTE: I thought that the dependencies were not added to the classpath, but i am not sure about this. However, i would expect Intellij to add dependencies to the classpath( or declare in the manifest file)
3. I also tried to use the gradle application plugin.
However this creates a zip/tar which contains a execute script and a bin folder which was not my intention.
So i started googling for hours and hours but i cann´t find a solution to my problem.
Come on this cannot be so hard - it is just so basic.
I am sure some genius can help me out and point me to my - probably stupid - failure.
My current solution is as follows:
I use gradle to build a jar containing all libs, I do this witha custom task called fatJar.
Here is a part from my build.gradle
apply plugin: 'java'
jar {
manifest {
attributes("Manifest-Version": "1.0",
"Main-Class": "com.randomPackage.MainClass");
}
}
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}
Then I just execute "gradle fatJar" on the command line and get a perfect jar.
I am attempting to make a test application using Gradle and Java that uses several libraries that use the Java Service Provider interface. I think this means that I need to modify META-INF but I am not really sure how to do this.
The error that I get is An SPI class of type org.apache.lucene.codecs.codec with nameLucene50does not exist. You need to add the corresponding JAR file supporting this SPI to your classpath. The current classpath supports the following names [ SimpleText]
I think that I need to get the SPI information into META-INF but I am not sure how to do this with Gradle.
Specifically, I am trying to use Lucene and Hadoop jars in the following build file:
apply plugin: 'java'
sourceCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
compile group:'org.apache.lucene', name:'lucene-core', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-queryparser', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-analyzers-common', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-facet', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-codecs', version:'5.0.0'
compile group:'org.apache.hadoop', name:'hadoop-hdfs', version:'2.6.0'
compile group:'org.apache.hadoop', name:'hadoop-core', version:'1.2.1'
compile group:'org.apache.hadoop', name:'hadoop-common', version:'2.6.0'
}
jar
{
from {configurations.compile.collect {it.isDirectory() ?it:zipTree(it) }}
manifest
{
attributes 'Main-Class': 'LuceneTest'
}
}
Both the lucene-core and lucene-codecs libraries provide org.apache.lucene.codecs.Codec implementations, so they both have a META-INF/services/org.apache.lucene.codecs.Codec service file. When you merge all your dependencies, both files are added to the jar file, but Lucene only sees the lucene-codecs one. You could merge the service files manually in the jar task, as in this post, which basically finds all the service files and combines them. The easier solution is probably to use something like the Gradle Shadow plugin.
If you add this to build.gradle, using the shadowJar task instead of the jar task should do what you want.
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.1'
}
}
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
mergeServiceFiles()
}
I have a Eclipse workspace with a declared workset configured to have several projects. Some are to generate JAR files and others are web applications that use those JAR files. In my architecture I have a JAR that will consist of domain core services and another one that depends on the first one that will consist of higher level services. Finally I will have some web applications that use those both JARs.
The first JAR project is build with Gradle, based on the following script
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral();
}
jar {
baseName = 'br.ufpr.unidades.dominio'
version = '0.1.0'
}
dependencies {
compile 'org.hibernate:hibernate-core:4.3.7.Final'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
As anyone can see, it´s a very simple build.gradle file and the build works fine with it. The expected JAR file is generated in the expected destination folder.
Now, here comes the build script for the second JAR:
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral()
}
jar {
baseName = 'br.ufpr.unidades.dominio.hibernate'
version = '0.1.0'
}
dependencies {
runtime fileTree(dir: '../dominio/build/libs', include: '*.jar')
compile 'org.hibernate:hibernate-core:4.3.7.Final'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
The second file is very similar to the first one, except it has a dependency on generated JAR:
runtime fileTree(dir: '../dominio/build/libs', include: '*.jar')
Eclipse doesn´t show any problems, but when I try to build the second JAR project I get many Class not found error messages, like the one below:
[sts] -----------------------------------------------------
[sts] Starting Gradle build for the following tasks:
[sts] build
[sts] -----------------------------------------------------
:compileJava
D:\Users\alex\Documents\Eclipse\workspace\unidades\dominio.hibernate\src\main\java\dominio\hibernate\HibernateCargoRepository.java:7: error: package unidades.dominio does not exist
import unidades.dominio.Cargo;
The message is clear: I´m importing a package that is not being found during the build, so the classes such a package has cannot be referenced in my code. Such a package is declared in the first and perfectly generated JAR file. It also is visible under Referenced Libraries item in the Eclipse project, so Gradle was able to find it to reference it in design time, but not to build the second JAR.
After all that, I suspect it´s a dependency management problem, but I can´t see which it is and how to fix it.
Thanks in advance!
Are You using classes from the jar under dominio/build/libs in the second project? If so, this should be a compile dependency. I'd also recommend setting a multimodule gradle project. Here are the docs.
I have the following list of JAR dependencies (the following is my entire build.gradle file):
apply plugin: 'java'
dependencies {
compile 'com.fasterxml.jackson.core:jackson-annotations:2.2.3'
compile 'com.wordnik:swagger-annotations:1.3.4'
compile 'javax.validation:validation-api:1.0.0.GA'
compile 'io.dropwizard:dropwizard-core:0.7.0'
compile 'io.dropwizard:dropwizard-client:0.7.0'
compile 'com.wordnik:swagger-jaxrs_2.10:1.3.4'
compile 'org.eclipse.jetty:jetty-servlets:8.1.14.v20131031'
}
I would like to run Gradle and have it pull all of these JARs (and their transitive deps) from Maven and place the JARs in a local lib directory.
When I run this I get a BUILD SUCCESSFUL message, but I don't see a lib directory under my main TestGradleroot` dir. I was expecting to see a directory that would contain all of these JARs as well as their transitive dependencies.
Try to use separate 'compile' for each library.
This is how it looks on mine android project:
dependencies {
compile 'com.google.android.support:wearable:+'
compile 'com.google.android.gms:play-services-wearable:+'
}
I'm very new to Gradle and the main reason I use it because I need to resolve dependencies issues for my compiled jar.
Here is my build.gradle file:
apply plugin: 'java'
apply plugin: 'eclipse'
version = '0.9'
jar {
manifest {
attributes 'Main-Class': 'wd.nlp.FileImport', 'Implementation-Title': 'WD\
NLP', 'Implementation-Version': version
}
}
repositories {
flatDir(dirs: 'lib')
}
dependencies{
compile 'mallet:mallet:2.0.7'
}
My Java files all depend on a third-party library called Mallet. Here is my folder structure:
|---1.10
|-----taskArtifacts
|-build
|---classes
|-----main
|-------wd
|---------nlp
|---dependency-cache
|---libs
|---tmp
|-----jar
|-lib
|-src
|---main
|-----java
|-------wd
|---------nlp
|-----resources
I placed Mallet-2.0.7.jar inside lib under the top folder. Then I used gradle build command and try to run my class:
java -classpath build/libs/JavaClassifier-0.9.jar wd.nlp.FileImport -train ...
Then I am told:
Exception in thread "main" java.lang.NoClassDefFoundError: cc/mallet/pipe/Pipe
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2531)
The Mallet library's path is cc.mallet.*...and now I don't know what to do...please help!
The dependency is not include because you don't create a distribution of you project. In Maven it is called an assembly.
If you call your application directly from the commandline it is not a matter of Gradle.
Anyway there is a Gradle plugin which creates a distribution and adds shell scripts to execute your application.
So when you add the following line to the gradle script.
apply plugin: 'application'
you will get some new tasks to create a distribution.