Gradle: How to exclude JAR from a WAR? - java

I have a multi-project Gradle build structure, where child project depends on a JAR, which I don't want to be in WAR file. I tried "exclude" but it does not work.
The main project script:
apply plugin: 'war'
war {
dependencies {
runtime (project(':childProject')) {
exclude group: 'javax.servlet.jsp', module: 'jsp-api'
}
}
}
The childProject script:
apply plugin: 'java'
dependencies {
compile 'javax.servlet.jsp:jsp-api'
}

I'm doing it this way.
war {
rootSpec.exclude("**/some-*.jar")
}

From the Gradle documentation
The War plugin adds two dependency configurations: providedCompile and
providedRuntime. Those configurations have the same scope as the
respective compile and runtime configurations, except that they are
not added to the WAR archive.
So, in other words, adding an entry to providedCompile or providedRuntime will cause that dependency to be excluded from the war file.
use providedCompile if you have source that relies on some classes for compiling
use providedRuntime if you use it for testing and not compiling.
http://www.gradle.org/docs/current/userguide/war_plugin.html
Example
providedCompile "javax.servlet:servlet-api:2.5"

I realised that providedCompile sometimes introduced dependencies issues for me, e.g. some classes are not found. I then figured out a more flexible solution.
We can just configure required dependencies as 'compile' and then exclude specific jars from the war file by using the following war configuration:
war {
classpath = classpath.filter { file ->
println file.name
(
!file.name.startsWith('gwt-dev') &&
!file.name.startsWith('gwt-user') &&
!file.name.startsWith('guava-gwt') &&
!file.name.startsWith('gwtbootstrap3') &&
!file.name.startsWith('gwtbootstrap3-extras') &&
!file.name.startsWith('servlet-api')
)
}
}
So far, I found this is the cleanest solution for me. I hope it helps.

I had the same problem but i found a generic solution based on the one of Jake W.
In your child-project, without the war plugin, you add your own providedCompile and providedRuntime like this:
configurations {
providedCompile
providedRuntime.extendsFrom providedCompile
}
plugins.withId('java') {
configurations {
compile.extendsFrom providedCompile
runtime.extendsFrom providedRuntime
}
}
In the project with your war file you copy this anywhere you want:
configurations.runtime.allDependencies.withType(ProjectDependency) { ProjectDependency dep ->
Project proj = dep.dependencyProject
evaluationDependsOn(proj.path)
Configuration cfg = proj.configurations.findByName('providedRuntime')
if (cfg != null){
war {
classpath -= cfg
}
}
}

The default behavior of the War task is to copy the content of src/main/webapp to the root of the archive. Your webapp directory may of course contain a WEB-INF sub-directory, which may contain all the dependencies of the runtime [1] configuration to WEB-INF/lib.
So to avoid load of other jar files or to decrease war file size, you may have to exclude jars during packaging. So, try adding rootSpec.exclude("/*.jar")** to exclude jars in war file like below.
war {
archiveName = "newproject.war"
rootSpec.exclude("**/*.jar")
destinationDir = buildDir
}

Related

Generate different gradle artifacts off single project or source

I have a huge legacy EAR project. Current build process uses Ant and I'm trying to convert to gradle.
The old Ant build uses a single source folder and everything is in there (EJB and WAR code together); then Ant uses different tasks to build EJB-JAR and WAR artifacts filtering by the package of interest (my.web.* for the WAR and my.ejb.* for the EJB).
It goes without saying that EJB and WAR heavily reference each other and I guess that's why they are compiled together even though separate artifacts are generated.
I have tried creating a parent EAR project, then separating my.ejb.* in an EJB subproject as well as my.web.* in a WAR subproject but gradle immediately complained about circular dependency and I haven't found a way around.
If above is not possible, then I am looking for recommendations on how to generate the EJB-JAR and WAR artifacts off the same codebase that would be compiled altogether, then include them in the EAR file as 'deploy' dependencies.
I have googled around but I am not very bright at gradle (obviously). Any help will be greatly appreciated.
I think you are falling into the trap that many of us have when trying to convert an existing ant project to Gradle for the first time - you are thinking of things the same 'ol ant way.
Instead, let Gradle do the work for you and it will be easier and the resulting build.gradle file much smaller and more concise.
Thinking in terms of having a parent ear project and a separate war project is good thinking however. But, you should take advantage of the plugins Gradle has to offer to simplify the task of constructing the archives.
Use the 'ear plugin':
https://docs.gradle.org/current/userguide/war_plugin.html
For example:
apply plugin: 'ear'
apply plugin: 'java'
repositories { mavenCentral() }
dependencies {
// The following dependencies will be the ear modules and
// will be placed in the ear root
deploy project(':war')
// The following dependencies will become ear libs and will
// be placed in a dir configured via the libDirName property
earlib group: 'log4j', name: 'log4j', version: '1.2.15', ext: 'jar'
}
ear {
appDirName 'src/main/app' // use application metadata found in this folder
// put dependent libraries into APP-INF/lib inside the generated EAR
libDirName 'APP-INF/lib'
deploymentDescriptor { // custom entries for application.xml:
// fileName = "application.xml" // same as the default value
// version = "6" // same as the default value
applicationName = "customear"
initializeInOrder = true
displayName = "Custom Ear" // defaults to project.name
// defaults to project.description if not set
description = "My customized EAR for the Gradle documentation"
// libraryDirectory = "APP-INF/lib" // not needed, above libDirName setting does this
// module("my.jar", "java") // won't deploy as my.jar isn't deploy dependency
// webModule("my.war", "/") // won't deploy as my.war isn't deploy dependency
securityRole "admin"
securityRole "superadmin"
withXml { provider -> // add a custom node to the XML
provider.asNode().appendNode("data-source", "my/data/source")
}
}
}
Then for your war, use the 'war plugin'. You can create the war as a separate project:
configurations {
moreLibs
}
repositories {
flatDir { dirs "lib" }
mavenCentral()
}
dependencies {
compile module(":compile:1.0") {
dependency ":compile-transitive-1.0#jar"
dependency ":providedCompile-transitive:1.0#jar"
}
providedCompile "javax.servlet:servlet-api:2.5"
providedCompile module(":providedCompile:1.0") {
dependency ":providedCompile-transitive:1.0#jar"
}
runtime ":runtime:1.0"
providedRuntime ":providedRuntime:1.0#jar"
testCompile "junit:junit:4.12"
moreLibs ":otherLib:1.0"
}
war {
from 'src/rootContent' // adds a file-set to the root of the archive
webInf { from 'src/additionalWebInf' } // adds a file-set to the WEB-INF dir.
classpath fileTree('additionalLibs') // adds a file-set to the WEB-INF/lib dir.
classpath configurations.moreLibs // adds a configuration to the WEB-INF/lib dir.
webXml = file('src/someWeb.xml') // copies a file to WEB-INF/web.xml
}
There is another helpful post on creating them as a single project, but that's definitely a bit more 'dicey':
https://discuss.gradle.org/t/single-project-with-jar-ejb-war-and-ear/5874

How to generate a jar with internal dependencies bundled and external dependencies as external jars?

I have a Gradle project which depends on sub-projects. I would like to create a "fat jar" containing all my sub-projects, and externel dependencies as external jars.
build.gradle:
dependencies {
compile project(':MyDep1')
compile project(':MyDep2')
compile 'com.google.guava:guava:18.0'
}
I would like to be able to generate the following output:
MyProject.jar -> Includes MyDep1 & MyDep2
libs/guavaXXX.jar -> Guava as external lib
I don't know how I could do this.
Use different configurations to hold your internal and external dependencies and package only one of those configurations into your project artifact.
configurations{
internalCompile
externalCompile
}
//add both int and ext to compile
configurations.compile.extendsFrom(internalCompile)
configurations.compile.extendsFrom(externalCompile)
dependencies{
internalCompile project(':MyDep1')
internalCompile project(':MyDep2')
externalCompile 'com.google.guava:guava:18.0'
}
in your fat jar task, include only from internalCompile
I finally made it work with this solution:
jar {
subprojects.each {
from files(it.sourceSets.main.output)
}
}
distributions {
main {
contents {
exclude subprojects.jar.archivePath.name
}
}
}
In my project's jar, I include the content of all subprojects ouputs. In the distribution, I exclude the jar from subprojects (so it only contains dependencies). This is probably not the best way, but it's simple and it works.

How do I include a single dependency in my JAR with Gradle?

I'm starting with Gradle and I was wondering how do I include a single dependency (TeamSpeak API in my case) into my JAR so that it could be available at the runtime.
Here is a part of my build.gradle :
apply plugin: 'java'
compileJava {
sourceCompatibility = '1.8'
options.encoding = 'UTF-8'
}
jar {
manifest {
attributes 'Class-Path': '.......'
}
from {
* What should I put here ? *
}
}
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '4.3.7.Final'
compile group: 'org.spigotmc', name: 'spigot', version: '1.8-R0.1-RELEASE'
// Many other dependencies, all available at runtime...
// This one isn't. So I need to include it into my JAR :
compile group: 'com.github.theholywaffle', name: 'teamspeak3-api', version: '+'
}
Thanks for your help :)
The easiest way is to start with a separate configuration for the dependencies you want to include. I know you only asked about a single jar but this solution will work if you add more dependencies to your new configuration. Maven has a well known name for this sort of thing called provided, so that is what we will use.
configurations {
provided
// Make compile extend from our provided configuration so that things added to bundled end up on the compile classpath
compile.extendsFrom(provided)
}
dependencies {
provided group: 'org.spigotmc', name: 'spigot', version: '1.8-R0.1-RELEASE'
}
jar {
// Include all of the jars from the bundled configuration in our jar
from configurations.provided.asFileTree.files.collect { zipTree(it) }
}
Using provided as the name of the configuration is also important because when the jar gets published, any dependencies you have in the providedconfiguration will show up as provided in the POM.xml that gets published with the JAR. Maven dependency resolvers will not pull down provided dependencies and users of your jar will not end up with duplicate copies of classes on the classpath. See Maven Dependency Scopes

How to recursively add a list of Jars to your classpath in gradle with groovy script [duplicate]

I have tried to add my local .jar file dependency to my build.gradle file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/model'
}
}
}
dependencies {
runtime files('libs/mnist-tools.jar', 'libs/gson-2.2.4.jar')
runtime fileTree(dir: 'libs', include: '*.jar')
}
And you can see that I added the .jar files into the referencedLibraries folder here: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1/referencedLibraries
But the problem is that when I run the command: gradle build on the command line I get the following error:
error: package com.google.gson does not exist
import com.google.gson.Gson;
Here is my entire repo: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1
According to the documentation, use a relative path for a local jar dependency as follows.
Groovy syntax:
dependencies {
implementation files('libs/something_local.jar')
}
Kotlin syntax:
dependencies {
implementation(files("libs/something_local.jar"))
}
If you really need to take that .jar from a local directory,
Add next to your module gradle (Not the app gradle file):
repositories {
flatDir {
dirs("libs")
}
}
dependencies {
implementation("gson-2.2.4")
}
However, being a standard .jar in an actual maven repository, why don't you try this?
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.2.4")
}
You could also do this which would include all JARs in the local repository. This way you wouldn't have to specify it every time.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
The following works for me:
compile fileTree(dir: 'libs', include: '*.jar')
Refer to the Gradle Documentation.
You can try reusing your local Maven repository for Gradle:
Install the jar into your local Maven repository:
mvn install:install-file -Dfile=utility.jar -DgroupId=com.company -DartifactId=utility -Dversion=0.0.1 -Dpackaging=jar
Check that you have the jar installed into your ~/.m2/ local Maven repository
Enable your local Maven repository in your build.gradle file:
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation ("com.company:utility:0.0.1")
}
Now you should have the jar enabled for implementation in your project
A solution for those using Kotlin DSL
The solutions added so far are great for the OP, but can't be used with Kotlin DSL without first translating them. Here's an example of how I added a local .JAR to my build using Kotlin DSL:
dependencies {
compile(files("/path/to/file.jar"))
testCompile(files("/path/to/file.jar"))
testCompile("junit", "junit", "4.12")
}
Remember that if you're using Windows, your backslashes will have to be escaped:
...
compile(files("C:\\path\\to\\file.jar"))
...
And also remember that quotation marks have to be double quotes, not single quotes.
Edit for 2020:
Gradle updates have deprecated compile and testCompile in favor of implementation and testImplementation. So the above dependency block would look like this for current Gradle versions:
dependencies {
implementation(files("/path/to/file.jar"))
testImplementation(files("/path/to/file.jar"))
testImplementation("junit", "junit", "4.12")
}
The accepted answer is good, however, I would have needed various library configurations within my multi-project Gradle build to use the same 3rd-party Java library.
Adding '$rootProject.projectDir' to the 'dir' path element within my 'allprojects' closure meant each sub-project referenced the same 'libs' directory, and not a version local to that sub-project:
//gradle.build snippet
allprojects {
...
repositories {
//All sub-projects will now refer to the same 'libs' directory
flatDir {
dirs "$rootProject.projectDir/libs"
}
mavenCentral()
}
...
}
EDIT by Quizzie: changed "${rootProject.projectDir}" to "$rootProject.projectDir" (works in the newest Gradle version).
Shorter version:
dependencies {
implementation fileTree('lib')
}
The Question already has been answered in detail. I still want to add something that seems very surprising to me:
The "gradle dependencies" task does not list any file dependencies. Even though you might think so, as they have been specified in the "dependencies" block after all..
So don't rely on the output of this to check whether your referenced local lib files are working correctly.
A simple way to do this is
compile fileTree(include: ['*.jar'], dir: 'libs')
it will compile all the .jar files in your libs directory in App.
Some more ways to add local library files using Kotlin DSL (build.gradle.kts):
implementation(
files(
"libs/library-1.jar",
"libs/library-2.jar",
"$rootDir/foo/my-other-library.jar"
)
)
implementation(
fileTree("libs/") {
// You can add as many include or exclude calls as you want
include("*.jar")
include("another-library.aar") // Some Android libraries are in AAR format
exclude("bad-library.jar")
}
)
implementation(
fileTree(
"dir" to "libs/",
// Here, instead of repeating include or exclude, assign a list of paths
"include" to "*.jar",
"exclude" to listOf("bad-library-1.jar", "bad-library-2.jar")
)
)
The above code assumes that the library files are in libs/ directory of the module (by module I mean the directory where this build.gradle.kts is located).
You can use Ant patterns in includes and excludes as shown above.
See Gradle documentations for more information about file dependencies.
Thanks to this post for providing a helpful answer.
I couldn't get the suggestion above at https://stackoverflow.com/a/20956456/1019307 to work. This worked for me though. For a file secondstring-20030401.jar that I stored in a libs/ directory in the root of the project:
repositories {
mavenCentral()
// Not everything is available in a Maven/Gradle repository. Use a local 'libs/' directory for these.
flatDir {
dirs 'libs'
}
}
...
compile name: 'secondstring-20030401'
The best way to do it is to add this in your build.gradle file and hit the sync option
dependency{
compile files('path.jar')
}
The solution which worked for me is the usage of fileTree in build.gradle file.
Keep the .jar which need to add as dependency in libs folder. The give the below code in dependenices block in build.gradle:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
You can add jar doing:
For gradle just put following code in build.gradle:
dependencies {
...
compile fileTree(dir: 'lib', includes: ['suitetalk-*0.jar'])
...
}
and for maven just follow steps:
For Intellij:
File->project structure->modules->dependency tab-> click on + sign-> jar and dependency->select jars you want to import-> ok-> apply(if visible)->ok
Remember that if you got any java.lang.NoClassDefFoundError: Could not initialize class exception at runtime this means that dependencies in jar not installed for that you have to add all dependecies in parent project.
For Gradle version 7.4 with Groovy build file
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation ':gson-2.2.4'
}
If you are on gradle 4.10 or newer:
implementation fileTree(dir: 'libs', includes: ['*.jar'])
Goto File -> Project Structure -> Modules -> app -> Dependencies Tab -> Click on +(button) -> Select File Dependency - > Select jar file in the lib folder
This steps will automatically add your dependency to gralde
Very Simple
Be careful if you are using continuous integration, you must add your libraries in the same path on your build server.
For this reason, I'd rather add jar to the local repository and, of course, do the same on the build server.
An other way:
Add library in the tree view. Right click on this one. Select menu "Add As Library".
A dialog appear, let you select module. OK and it's done.

Confused about dependencies in local respository(gradle)

I trying to compile and package up my java application but I am facing issues when trying to specify my local repository in which I have my jars that will be used as dependencies. I have stored all the jars I need for my application in '/home/test/lib'. What I have as my build.gradle file is as follows:
apply plugin:'application'
apply plugin:'java'
apply plugin:'idea'
def repositoryPath = '/home/test/lib'
repositories {
repositoryPath
}
dependencies {
"org.springframework:spring-orm:3.0.2.RELEASE"
"org.springframework:spring-context-support:3.0.2.RELEASE"
'commons-dbcp:commons-dbcp:1.4'
'org.apache.ibatis:ibatis-sqlmap:2.3.4.726'
'commons-dbutils:commons-dbutils:1.3'
'joda-time:joda-time:1.6'
'commons-lang:commons-lang:2.5'
'com.google.collections:google-collections:1.0'
}
jar {
baseName = 'testJar'
}
mainClassName = "com.some.test.testRunner"
When I run gradle build, I am getting "package * does not exist" errors.
My assumption is that gradle is not finding the requisite external jars in my lib folder. Can somebody point out what I may be doing wrong here.
Thanks
some remarks about your build file. I assume you have a flat directory in '/home/test/lib' that contains your third party libs? If this is the case you can use a flatDir repository, that is declared with the following syntax:
def repositoryPath = '/home/test/lib'
repositories {
flatDir {
dirs repositoryPath
}
}
If /home/test/lib is a ivy repository, you can do:
repositories {
ivy {
url repositoryPath
}
}
This is explained in detail in the Gradle user guide.
in your 'dependencies' section you missed to declare the scope of your dependencies (compile, runtime, etc):
dependencies {
compile "org.springframework:spring-orm:3.0.2.RELEASE"
compile "org.springframework:spring-context-support:3.0.2.RELEASE"
compile 'commons-dbcp:commons-dbcp:1.4'
compile 'org.apache.ibatis:ibatis-sqlmap:2.3.4.726'
compile 'commons-dbutils:commons-dbutils:1.3'
compile 'joda-time:joda-time:1.6'
compile 'commons-lang:commons-lang:2.5'
compile 'com.google.collections:google-collections:1.0'
}
if you use a flatdir repository, the group of your dependency definition is often omitted:
dependencies {
compile ":spring-orm:3.0.2.RELEASE"
...
}
Have a look at the gradle user guide for detailed information about dependency handling with gradle: http://gradle.org/docs/current/userguide/userguide_single.html#artifact_dependencies_tutorial
regards,
René

Categories