So I have a multi project setup that looks something like this
Root Project
--> common
--> project1
--> project2
--> 3rd_party_api
So common obviously contains a bunch of code shared across the other projects. Projects 1 and 2 are fine because they are wars and contain the common jar file as a dependency without any issues.
The problem I have is with my 3rd_party_api project. This is quite a small jar file that we will be delivering to other teams so that they can integrate with our code. Most of the java code required is contained in this project folder however there are 3 or 4 classes that are in the common project and need to be included in this library. Because it has to be standalone I need to wrap those classes in the jar file.
I have tried various iterations of srcDirs and source but I can't for the life of me figure out an easy way to do this.
As I've said I've looked at different approaches but my latest attempt looked a bit like this:
project(':api') {
defaultTasks 'jar'
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir fileTree(dir: '../common/src/main/java').matching { include 'com/my/classes/**' }
}
}
dependencies {
compile project(':common')
}
}
This compiles successfully but the extra classes from common are not included in the jar.
Any help would be greatly appreciated.
Thanks Dirk,
Didn't quite work for me but got me thinking about other approaches. I eventually got it to do what I needed using a custom jar task. Something like the following:
defaultTasks 'lib'
dependencies {
compile project(':common')
}
task lib( type: Jar, dependsOn: classes) {
from sourceSets.main.output
from (project(':common').sourceSets.main.output) {
include 'com/myclasses/stuff/**'
include 'com/specificclass/MyClass.class'
}
}
maybe something like:
jar {
baseName = 'yourJarFileName'
from('path/to/your/dir/') {
include 'local/path/from/there/**/*.jar'
}
}
didn't checked this ... so don't blame me if it does not work out of the box ;)
other possibility would be to define your custom sourceSets ... but never tried this either.
Related
I've tried everything by now, so I hope someone in here can tell me more...
Im trying to produce an executable .jar from a IntelliJ Gradle JavaFX project. I used the standard setup that IntelliJ provided, I changed the Gradle.build file however.
The new file I got from here: Non-Modular Gradle (openjfx.io)
I have a main class that has some basic code in it and a launcher class that does not extend Application and is specified as the Main class in the jar manifest.
For now I only use javafx.controls and basically everything is as the example they provided here.
When doing the ./gradlew jar command I get the error:
no module-info.java found
Which - as I understand - is not required if I use the Non-Modular approach?
However if I add it I get the error:
Entry module-info.class is a duplicate but no duplicate handling strategy has been set.
I tried every other option out there, all of them lead to either the 2. error or the jar was produced but not executable due to the fact that it can't find the Application class...
Any help is greatly appreciated.
I just want to point out that I've never really used Gradle before and have never formally learned any coding, but can fiddle my way around usually.
For the sake if it my build file:
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.9' // this is old right?
}
repositories {
mavenCentral()
}
dependencies {
/* uncomment for cross-platform jar: */
runtimeOnly "org.openjfx:javafx-graphics:$javafx.version:win"
runtimeOnly "org.openjfx:javafx-graphics:$javafx.version:linux"
runtimeOnly "org.openjfx:javafx-graphics:$javafx.version:mac"
}
javafx {
version = "16"
modules = [ 'javafx.controls' ]
}
mainClassName = 'main.class.with.Code'
jar {
manifest {
attributes 'Main-Class': 'main.class.with.Launcher'
}
from {
// this is what causes the module duplicate error I think (at least it did in my other tries)
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
I'm attempting to include a generated pom.xml in the jar that I'm creating with gradle.
So far, in my parent project, I have
subprojects {
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}
}
and in the sub-project I have:
tasks.build.dependsOn install
sourceSets {
main {
resources {
srcDirs = [ "src/main/resources", "build/poms" ]
}
}
}
This will generate ./build/poms/pom-default.xml, but it will not add it to the JAR.
Creating a dependency on an earlier phase than build creates circular dependencies (and I don't know whether this is the problem anyway).
Also, I'd like the pom.xml to show up inside META-INF with name pom.xml (not pom-default.xml), so this may not be the right approach anyway.
Somehow I'm thinking it can't be as complicated as this looks?
You should be able to include the POM in your JAR by adding the following to your subprojects closure:
jar {
into("META-INF/maven/${project.group}/${project.name}") {
from generatePomFileForMavenPublication
rename { it.replace('pom-default.xml', 'pom.xml') }
}
}
If you already have a jar closure, you can add it there. This automatically creates a task dependency on the generatePomFileForMavenPublication task, so that the POM file is there when the JAR is created.
The sourceSets part from your question would not be required for this.
(Side note: It would not be strictly necessary to do this at all, because the Maven publish process will publish the POM as an individual artifact anyway.)
This is currently my build.gradle file (I removed unnecessary task references, which are not only working perfectly fine, but are irrelevant to the current question):
buildscript {
repositories {
jcenter()
maven {
name = 'forge'
url = 'https://files.minecraftforge.net/maven'
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.1-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'java'
dependencies {
compile('some.library:here:1.2.3') // no extra modules
compile('other.library:here:4.5.6') // multiple modules
}
jar {
from project.configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
Currently I have a system which will automatically pack all the dependencies into my jar file. The main issue I have is that if another mod or file loads the same library before my mod, I will end up with a class loading problem, because I'll be loading the same class twice (one from another jar, and one from my own).
With that being said, is it possible to avoid such an issue? How would I realistically account for such a thing? Does forge perhaps have a method to control class loading to the extent that duplicate libraries will not be loaded, hence there will be no class conflicts?
Minecraft Forge supports a feature called shading to deal with this problem. When you shade a jar, it's integrated into your jar, but the package is renamed to something unique (along with all references to it from your code).
Source: https://github.com/MinecraftForge/ForgeGradle/blob/FG_1.2/docs/user-guide/shading.md
I'm using the approach from Gradle - extract file from depended jar to extact a .so file from inside a native JAR.
configurations {
special
}
dependencies {
special('org.jogamp.jogl:jogl-all:2.3.2:natives-linux-i586')
}
task extract(type: Copy) {
from({ zipTree(configurations.special.singleFile) })
include 'natives/linux-i586/*.so'
into "$buildDir/extracted"
}
This works fine, however it appears to break compilation of code that depends on org.jogamp.jogl:jogl-all:2.3.2, the non-native Java part.
TestJogl.java:1: error: package com.jogamp.opengl does not exist
import com.jogamp.opengl.GL;
The compilation fails if the project is built with clean extract build but not clean build
I've simplified the code to
import com.jogamp.opengl.GL;
public class TestJogl {
private GL gl;
}
and corresponding build.gradle
apply plugin: "java"
dependencies {
compile "org.jogamp.jogl:jogl-all:2.3.2"
}
I've isolated this issue to the usage of "flatDir" repo. The exact same project compiles fine when using mavenCentral(). Note using a legacy corporate network without artifactory or direct Internet access.
allprojects {
repositories {
flatDir {
dirs "$rootProject.projectDir/local-repo"
// contains jogl-all-2.3.2-natives-linux-i586.jar
// jogl-all-2.3.2.jar
}
}
}
I've managed to work around the issue by changing the dependency to explicity specify #jar, which should be implicit
compile "org.jogamp.jogl:jogl-all:2.3.2#jar"
The same problem occurs in both single and multi project layouts.
My analysis: This is a bug in Gradle. Somehow when using flatDir Gradle gets confused and thinks that the dependency has been setup, but uses the native JAR instead of the Java JAR.
Questions: Am I doing something wrong? Is this a bug? Is there another way to workaround it?
Environment: Gradle 3.5, JDK 1.8u144
I have the following project:
-> root
->->common
->->server
->->client
I want the server and client projects to both access files from the same resource folder.
My root's build.gradle looks like the following:
apply plugin: 'java'
allprojects {
apply plugin: 'java'
apply plugin: 'idea'
}
subprojects {
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.8.1'
}
}
The multi-project system works and I have no issues with it. I have found resources for implementing resource folders but they're only at a per-project level.
I'd appreciate any insight and help in this. :)
If you have resources you want shared across projects you should create a library for those resources, and have each project depend on that library. Take a look at the Android documentation on library modules.
Also, take a look here for an example of how to add a project dependency to your Gradle build script.
In case you prefer not to have another artifact then another option would be to merge the client/server code with the common code before building (e.g. $buildDir/src) and pointing the srcDir to this location.
In order to do this:
Add a prepareSources task of type Copy that will copy all relevant sources both from client/server and common into alternative src/main folder (e.g. under $project.buildDir/src)
Rename the src/main folder in the server/client modules to something else. This is needed as the java plugin automatically includes this folder in srcDir while we want to take these sources from the merged sources location.
Make compileJava and processResources dependent on the new prepareSources task:
compileJava.dependsOn prepareSources
processResources.dependsOn prepareSources
Add the new src directory to srcDir