[Forge 1.8.9]: Including dependencies in JAR - gradle

I've been making a Forge mod for Minecraft 1.8.9 with the Forge MDK. So far my mod has 1 dependency, which is SnakeYAML. I added this line: compile 'org.yaml:snakeyaml:1.30' to my build.gradle file, so that I have SnakeYAML during development, but it doesn't get included when I build the JAR. Is there any way to include SnakeYAML in my JAR as well?

You can create a fat Jar. In summary, a fat Jar contains all of the dependency classes and resources in a single output Jar. I assume you're using Gradle as this is a Forge project.
Add the Shadow plugin
plugins {
id 'com.github.johnrengelman.shadow' version '7.1.2'
id 'java'
}
Then configure your dependencies to shadow in SnakeYAML:
dependencies {
implementation 'org.yaml:snakeyaml:1.30'
...
shadow 'org.yaml:snakeyaml:1.30'
}
Finally, use the ShadowJar task added under 'Shadow' to build your fat Jar. You may need to change the version of Shadow for the gradle version you're using. Refer to the documentation for any configuration you may wish to add.

Related

How to build a jar from a multi-module project when using Gradle?

I'm working on a multi-module library project which I build with Gradle. I have a dependency to another module of this project in my dependencies section:
dependencies {
compile project(':my-other-module')
}
My problem is that I want to build a .jar file which only contains the local modules in the final file, not its transitive dependencies. I tried this:
jar {
from project(':my-other-module').configurations.compile.collect { zipTree it }
}
but this added all the transitive dependencies as well. I want to create a .jar which only contains my own files, so the users of this library can have their own versions of transitive dependencies. How can I do so?
Further clarification:
I have dependencies declared in my project to external jars like apache-commons. I want these not to be in my resulting .jar file but I want the users of my library to be able to just add my library as a dependency and let Maven/Gradle download the transitive dependencies. I don't want these transitive dependencies to be in the .jar file I deploy to Maven Central. compileOnly is not an option since the dependencies I use like apache-commons are not provided by a framework or a container. They need to be present as compile dependencies. I just want to build and deploy a .jar file which has all the files in my project which has multiple modules.
I am not sure it'll help you or not but, you can try this.
In your build.gradle file, customize your jar task as follows:
// This closure will return the full directory path of folder where your classes are built
ext.moduleClassPath = { moduleName ->
def classOutputDirConst = "/classes/java/main"
return "${project(":${moduleName}").buildDir}${classOutputDirConst}"
}
// Now jar task will include only the built file of specified project
jar {
from(moduleClassPath("projectName1"), moduleClassPath("projectName2"))
}
Check the reference for the from(SourcePaths) method here: Reference: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object[])
Gradle has a compile-only dependency concept, similar to Maven's provided scope:
Compile-only dependencies are distinctly different than regular compile dependencies. They are not included on the runtime classpath and they are non-transitive, meaning they are not included in dependent projects.
The dependencies you don't want can be declared in the compileOnly configuration, rather than compile, eg:
dependencies {
compileOnly 'javax.servlet:servlet-api:2.5'
}
compileOnly is not even visible to unit tests, by default. We change this in a common gradle snippet which we include in each build:
// compileOnly isn't visible to tests by default, add it
plugins.withType(JavaPlugin).whenPluginAdded {
sourceSets {
test.compileClasspath += configurations.compileOnly
test.runtimeClasspath += configurations.compileOnly
}
}
For the second part, for which I believe you want to create a single "fat" jar,
I would suggest creating your jar using the very good Shadow Plugin, rather than manually extending the jar task. By default, the shadow plugin will not include anything in the compileOnly configuration in the resulting jar.

What is supposed to happen to dependencies after gradle build?

I am trying out Gradle, and am wondering, what is supposed to happen to a project's dependencies after you run gradle build? For example, my sample projects don't run on the command line after they are built, because they are missing dependencies. They seem to compile fine, as gradle doesn't give me errors or warnings about finding the dependencies.
Gradle projects I've made in IntelliJ Idea have the same problem. They compile and run inside the IDE, but are missing dependencies and can't run on the command line.
So what is supposed to happen to the dependencies I declare in the build.gradle file? Shouldn't they be output somewhere together with my .class files? Otherwise, what is the point of gradle when I could manage this by editing my classpath?
Edit: Here is my build.gradle file:
apply plugin: 'java'
jar {
manifest {
attributes('Main-Class': 'Animals')
}
}
repositories {
flatDir{
dirs "D:\\libs\\gradleRepo"
}
}
dependencies {
compile name: "AnimalTypes-1.0-SNAPSHOT"
}
sourceSets{
main{
java {
srcDirs=['src']
}
}
}
Your Gradle build only takes care of the compile time and allows you to use the specified dependencies in your code (it adds them to the compile classpath). But it does not take care of the runtime. Once the JAR is build, you need to specify the runtime classpath and provide all required dependencies.
You may think, that this is bad or a disadvantage, but actually it is totally fine and intended, because if you build a Java library, you won't need to execute it, you just want to specify it as a dependency for another project. If you would distribute your library to a Maven repository, all dependencies from Maven repositories (module dependencies) would end up in a POM descriptor as transitive dependencies.
Now, if you want to build a runnable Java application, simply use the Gradle Application Plugin (apply plugin: 'application'), which will create a ZIP file containing the dependencies and start scripts providing your runtime classpath for execution.
Third-party plugins can also produce so-called fat JARs, which are JAR files with all dependencies included. It depends on your use case if you should use them, because often dependency management via repositories is the better way to go.

Gradle include jar produced by another project in war

Currently I have two projects with gradle build.gradle. The first is going to create a fat jar file, which I would like to include in a war file. I thought compiling it would be enough, but it doesn't seem to be ending up in the /lib directory of my war file. Anyone have thoughts I am quite new to gradle.
dependencies {
compile project(':JarProject')
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
providedCompile 'org.apache.tomcat:tomcat-jsp-api:7.0.55'
}
war {
archiveName 'WarProject.war'
from 'JarProject/build/libs'
webXml = file('src/web.xml')
}
Does the second project war need to be in providedRuntime? Or should I publish the jar from the other project in the local maven repo and include it that way?
The War task essentially behaves like a CopyTask with regards to stuff it packs in the war, so the documentation on working with files is useful. In essence, I think you need something like (untested):
from fileTree('JarProject/build/libs') {
into("lib")
}
That being said, using mavenLocal() and publishing there also works, but it can lead to unexpected results when the war includes some old version from local, picking up the jar explicitly from the file system like above is better.
I think the elegant solution would be to use multi project builds and project level dependencies. You would have the two builds as separate projects of the same Gradle build and add the "jar project" as a regular compile dependency.
How have you declared the dependency? I assume you have a multi-project build with subprojects A and B, both using the War plugin. I made an experiment using Gradle 2.4 and if I declare B/build.gradle like this:
apply plugin: 'war'
dependencies {
compile project(':A')
}
then B.war contains WEB-INF/lib/A.jar. If you correctly follow conventions of Gradle War plugin (place web resources in A/src/main/webapp/ and code-related resources in A/src/main/resources/), then A.jar should contain what you want.
see this

Set classpath from Gradle Plugin

When writing a gradle plugin, is it possible to add dependencies to the compile and testCompile classpath for projects that apply the plugin?
If so, is there a simple example that you can reference?
As an example; let's say I wanted to write a plugin that, among other things, added the AWS Java API jars to a project i.e. I get the the jars on the classpath of the project where I apply the plugin allowing me to compile against them.
Thanks
I am not fully sure I understand the question but you can look at the gradle war plugin (https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/groovy/org/gradle/api/plugins/WarPlugin.java) which defines new tasks providedCompile which extends compile
Edit : making plugin with its dependencies
In your example, its totally possible that the plugin defines its own dependencies like in a normal build.gradle file
repositories {
mavenCentral()
}
dependencies {
compile "com.amazonaws:aws-java-sdk-ec2:1.10.2"
}
see for example the was plugin (https://github.com/classmethod-aws/gradle-aws-plugin/blob/develop/build.gradle) when you apply this plugin in your own build the aws dependencies will be downloaded and available to your build.

How do I define a simple Gradle project with only a single jar file?

I have a Gradle project that depends on an external jar file. Currently I'm defining the dependency like this:
dependencies {
compile files('/path/to/my/jar/library.jar')
}
However I want to include it as a project dependency instead, like this:
dependencies {
compile project(':whatGoesHere?')
}
I assume I need to define a new Gradle project that contains the jar file but I don't know how to do this. I'm wondering about things like:
Do I just need to create a new build.gradle or are there more steps?
What would go in the build.gradle file?
Assume the new project contains nothing but the jar file (since it does). Also assume I know almost nothing about Gradle (because I don't!).
P.S. If it matters, this is an Android Gradle project.
As a roundup for our discussion, I'll bring simple example of "build.gradle" file, using maven local and maven central repositories:
apply plugin: 'maven'
apply plugin: 'java'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'commons-io:commons-io:2.4'
testCompile 'junit:junit:4.11'
}
Explanation:
"apply plugin: 'maven'" enables maven plugin, which is needed for dependency download.
"apply plugin: 'java'" enables java compilation tasks for your project.
"repositories" declares one or more repositories (maven or ivy), from where artifacts (jar libraries) will be downloaded.
"mavenLocal" refers to so-called local maven repository, which is located in "~/.m2/repository" folder on your computer. local maven repository effectively caches external repositories, but it also allows installation of local-only artifacts.
"mavenCentral" refers to maven central.
"dependencies" lists your project dependencies, either other projects or artifacts (jars).
"compile" is a configuration supported by "java" and "groovy" plugins, it tells gradle: "add these libraries to the classpath of the application during compilation phase".
"testCompile" is another configuration supported by "java" and "groovy" plugins, it tells gradle: "add these libraries to the classpath of the application during test phase".
'commons-io:commons-io:2.4' is "coordinates" of the artifact within maven repository, in form group:name:version.
You can search for well-known java libraries at address: http://mvnrepository.com/ and then include their coordinates in "build.gradle". You don't need to download anything - gradle does it for you automatically.

Resources