How to include subproject classes in jar? - java

After hours of researching and trying I hope that someone can explain how we can have Gradle including classes of one or more subproject into a specific jar.
Lets say we have just three modules
Core
App
Web
Obviously the App and Web project artifacts (jars) should contain all classes from the Core project.
Settings gradle:
rootProject.name = 'MyProject'
include 'MyProjectCore'
include 'MyProjectApp'
include 'MyProjectWeb'
MyProjectApp / MyProjectWeb:
...
dependencies {
...
compile project(':MyProjectCore')
}
The projects can be compiled but the output jars do not contain the core classes.

Okay finally I found a working solution even if it might not be the best.
For the App and Web projects I overwrite the jar task like this to add the source sets of the Core module.
jar {
from project.sourceSets.main.allSource
from project(":MyProjectCore").sourceSets.main.java.srcDirs
}

With this you can add all *.class files created in your subprojects into your jar automatically:
jar {
from {
subprojects.collect { it.sourceSets.main.output }
}
}
To make sure the .class are there, make sure the root project depends on the subprojects:
dependencies {
compile project(':mySubProject')
}

Related

Gradle - one project, multiple packages, multiple jars

I'm asking you about a very basic question but I hope you can find the time to help me:
I'm trying to realise a java-project, that can spit out several different programs which partially have dependencies on other projects of mine.
In order to keep it simple, I want to have all the code in one project, run by Gradle, so if I make changes to a central library (the database connector for example) all the child-programs automatically recieve the changes.
An example could look like this:
project:
program_A
central_library
program_B
output:
program_A.jar (including central library)
program_B.jar (including central library)
Now I'm having serious troubles finding a correct buildscript for this and was wondering if someone here could help me out.
P.S. : Since I'm new to this, if I should realize this through different modules within the Gradleproject instead of different packages in the Gradleprojects sourcefile, feel free to tell me :)
One way to approach this is to have a root project, that holds the three other projects inside of it.
Specify the sub-projects inside its settings.gradle file:
rootProject.name = 'RootProject'
include 'program_A'
include 'central_library'
include 'program_B'
With this in place, program_a can depend on central_library by adding a dependency in its build.gradle:
dependencies {
compile project(':central_library')
}
I have a similar setup in one of my projects, although the "central library" is the root project and the submodules are test environments.
Create a root directory and put each library or program into its own sub-directory.
Create a gradle project in each subproject.
You can for example create a skeleton gradle project by running
gradle init --type=java-library
or
gradle init --type=java-application
Then in the root directory create a gradle multi-module project. Basically
run only
gradle init
and then create a settings.gradle and list all sub-projects there.
This is actually described very well in the gradle documentation:
https://guides.gradle.org/creating-multi-project-builds/
If I understand correctly, what you want to do is, when you change your local projects, you want other projects to see those details. For this you need to publish your projects to some kind of repo, like maven repo. You can do this from command line gradle publishToMavenLocal, or gradle build pTMl. You can also do this in build.gradle file with something like the following:
task sourceJar (type : Jar) {
classifier = constants.extSources
from sourceSets.main.allSource
}
publications {
mavenJava(MavenPublication) {
from components.java
artifact(sourceJar) {
classifier "sources" //classifier = constants.extSources
}
}
}

Outsource java packages for reuse in other projects with gradle

Ive got an Project an within it,I developed a bunch of classes wich is kept very abstract so I could use it in other projects. How should I outsource the package in a way so I can include it via gradle or by the IDE in the end?
Also the reusable packag-content is still in development so I want do work on it in paralelle.
Can anybody tell me how to solve this?
In your build.gradle use a custom build to collect only the package that you want
task customBuild(type: Jar) {
from ("src/main/java/abstract/"){
into "abstract"
}
version = ""
baseName = "myClasses"
}
it will build you a jar file inside build/libs/YouJarName
Now you can copy the jar to anywhere you want, and include it in another project in that way :
dependencies {
compile fileTree (dir : "your/jar/location", includes: ["myJar.jar"])
}

How to add root Project as classpath in Gradle

In JAVA eclipse, the main class of the java project is defined as one of the class in the JAR of the 'lib' folder, and the root project (fooBar) is added as a dependency in the classpath.
This can be acheived in eclipse by simply adding the root project in the classpath. However, how do we add the dependency of the root project in gradle?
dependencies {
compile project(':fooBar');
}
> Project with path ':fooBar' could not be found in root project 'fooBar'.
The following is the project structure:
fooBar
-src/main/java
-src/test/java
-JRE System Library
-gradle
--wrapper
--launch.gradle
-lib
-build.gradle
-settings.gradle
-gradle-apps.settings
-gradle.properties
-gradlew
-gradlew.bat
I guess I got your point. First of all I have a doubt. Why are you adding
dependencies {
compile project(':fooBar');
}
this entry in build.gradle of fooBar project? This can cause cyclic dependency and results in build failure.
So I guess remove the above entry from build.gradle of fooBar project.
And please add the below code in your settings.gradle file:
rootProject.name = 'fooBar'
include ':fooBar'
Hope this will work.
As far as the project method is concerned, the root project has no name. So this is the syntax in the subproject's build.gradle:
dependencies {
compile project(':')
}
However, it is rarely a good idea to do this. It is too easy to end up with circular dependencies. Most multi-module projects have a separate "main" projects (called something like "main", "core" or "base"), and other modules can easily depend on that using compile project(':core') or whatever.
(Originally answered over here.)

Basic gradle Q for multiple projects

This is a basic gradle question but I could not find an answer:
If I have multiple independent projects that share the same root directory, how should I use different build.gradle file for them?
for example the directory structure is like this:
src/main/java/package1/base1/project1package/
src/main/java/package1/base1/project2package/
It looks like the build.gradle file should be placed at root, but how to differ two projects which are totally independent and not related to each other? When I use gradle build command, how can I specify one project to be built? Thanks.
To be honest I don't like the structure you are proposing. The standard one looks like this:
<root>/build.gradle
<root>/<subproject1>/build.gradle
<root>/<subproject1>/src/main/java/<basepackage>/<subproject1>/
<root>/<subproject2>/build.gradle
<root>/<subproject2>/src/main/java/<basepackage>/<subproject2>/
The subproject1 and subproject2 are independent of each other. Moreover:
<root>/build.gradle can contain a build configuration, tasks and so on common to all sub-projects. subproject1-specific stuff is then in <root>/<subproject1>/build.gradle
If you execute gradle build in <root>/, all sub-projects will be built. If you do this in <root>/<subproject1>/, only the subproject1 will be built.
For more, see http://www.gradle.org/docs/current/userguide/multi_project_builds.html
Let me know if I am off base, but essentially what I think you want to do is simply produce two separate JARs from two sets of source that happen to live in the same root directory. This is a pretty funny way to structure your project, as #Tomas mentioned, but assuming you cannot change your project structure, you could simply create custom source sets to solve this problem.
Your build could look something like this.
apply plugin: 'java-base'
sourceSets {
projA {
java {
srcDir 'src/main/java'
include 'pkg1/**'
}
}
projB {
java {
srcDir 'src/main/java'
include 'pkg2/**'
}
}
}
task projAJar(type: Jar) {
baseName 'projA'
from sourceSets.projA.output
}
task projBJar(type: Jar) {
baseName 'projB'
from sourceSets.projB.output
}
Although this is technically one Gradle project, these two source sets each have their own compile tasks, jar tasks, and configurations. You would configure your dependencies like so.
dependencies {
projACompile 'foo.org:lib:1.0'
projBCompile 'bar.org:lib:2.0'
}

Dynamically add JAR to Gradle dependencies

Currently, my build.gradle has a dependency on an external library built with Ant. To accomplish building the library, I followed the advice here and created a task which builds the external library, and copies it to the libs/ folder.
The task is called as part of a dependency:
build.gradle
dependencies {
compile fileTree('libs') {
include '*.jar'
builtBy 'myTask'
}
}
task myTask (type: GradleBuild) { GradleBuild antBuild ->
antBuild.buildFile('external-stub.gradle')
antBuild.tasks = ['clean', 'ivy.check', 'ivy.download', 'ivy.task', 'ivy',
'init', 'mergeCode', 'compile', 'jar', 'copyJarsToProject']
}
However, when the compile actually runs, the library I just built and copied in is not included in the dependencies, as evidenced by a whole lot of compilation errors.
Am I including the library the wrong way?
The full build.gradle and associated files are over at Github, and I've linked to the specific commit I'm having issues with: Source Repository
Alright, took me a while to get a build I was happy with. But, here's what was changed.
The actual build of the JAR was built using the same style, but moved to the external project (so that the main build project wasn't reaching across to it). I'll give an in-depth explanation below, but the commits are here and here. These are in order.
Basically, we export the jar as an artifact that other projects can depend on, rather than copying over the Jar ourselves. This way, the Ant build runs and other projects can see the Jar we just created. This is the end of the first commit. In the second commit, the task outputs are marked as needing to be regenerated only if the Jar does not exist. This was due to the fact that whenever I tried to build the app, it would take minutes to regen the Jar, and then have to repackage everything else as well. The code is below:
build.gradle External Project
configurations {
buildJSword
}
task doBuildJSword (type: GradleBuild) {
buildFile = 'jsword-stub.gradle'
tasks = ['clean', 'ivy.check', 'ivy.download', 'ivy.task', 'ivy',
'init', 'mergeCode', 'compile', 'jar'] //, 'copyJarsToMinimalBible']
ext.outputJar = file('distribution/jsword.jar')
outputs.upToDateWhen {
ext.outputJar.exists()
}
}
artifacts {
buildJSword(doBuildJSword.ext.outputJar) {
builtBy doBuildJSword
}
}
Then, the main project just has to add this project as a compile-time dependency:
build.gradle Main Project
compile project(path: ':jsword-minimalbible', configuration: 'buildJSword')
Hope this is helpful for anyone with a similar issue, let me know if you have questions!
Note: The build currently does not clean itself properly, so if you change any code in the external project, you need to delete the external Jar for everything to regenerate itself correctly.

Categories