Gradle - one project, multiple packages, multiple jars - java

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
}
}
}

Related

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"])
}

Gradle Transitive Dependencies from Modules

Disclaimer:
I'm new to Gradle, have read a lot of docs, and I don't know whether my maven-style understanding is tripping me out, or whether it's the sleep dep (kids - don't ask), but I'm still not getting it.
Problem Background:
I have a project that consists of several modules.
One of the modules, let's call it data-structure defines a data structure
Another module, data-structure-fabsearch, defines an implementation for a data source for the data structure, and finally
A third module, fabsearch-common, defines some common data source classes (eg: connection management to a fabsearch data source etc).
The reason I've done it like this is because there's actually another module that also uses the fabsearch-common stuff.
Anyway, my data-structure-fabsearch build.gradle looks something like this:
dependencies {
compile project(:data-structure)
compile project(:fabsearch-common)
}
The fabsearch-common module declares depedencies for the fabsearch api (let's call it fabsearch-api-1.0.0).
So, the dependency tree for data-structure-fabsearch should look like this:
- data-structure-fabsearch
- data-structure
- fabsearch-common
- fabsearch-api-1.0.0
This was all working wonderfully last night. This morning I came to work and all of a sudden those dependencies don't resolve anymore. References to fabsearch-api-1.0.0 classes are no longer found.
What I've Tried
1. In the parent build.gradle:
project(':data-structure-fabsearch'){
apply plugin: 'java'
dependencies {
compile project(path: ':data-structure', configuration: 'compile')
compile project(path: ':fabsearch-common', configuration: 'compile')
}
}
I've tried this with and without the configuration setting.
2. In the data-structure-fabsearch build.gradle file, adding the configuration parameter.
3. Restarting IntelliJ
4. Clicking the refresh icon in the Gradle tool window (repeatedly)
5. Reading all about transitive dependencies in the Gradle user guides
6. Drinking tea (repeatedly)
None of the above work.
What I'm Expecting
I'm expecting that the fabsearch-common dependencies (the fabsearch-api jars) should also be included in the data-structure-fabsearch dependency tree. All references to fabsearch-api classes in data-structure-fabsearch should resolve etc etc.
My Question[s]
Whilst this is possible in Maven, is it possible in Gradle?
What do I have to do to get it to work?
How much sleep dep can you take without dying?
Many thanks for any help.
Turns out the problem wasn't gradle at all. The problem was IntelliJ.
It got it's knickers into a proper twist!
Solution:
1. Close the project in IntelliJ
2. Delete the .idea directory
3. Delete all .iml files and any other IntelliJ cra-useful files
4. Open project in IntelliJ, choose same directory. Problem disappears.

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.

How can I import one Gradle script into another?

I have a complex Gradle script that wraps up a load of functionality around building and deploying a number of NetBeans projects to a number of environments.
The script works very well, but in essence it is all configured through half a dozen maps holding project and environment information.
I want to abstract the tasks away into another file, so that I can simply define my maps in a simple build file, and import the tasks from the other file. In this way, I can use the same core tasks for a number of projects and configure those projects with a simple set of maps.
Can anyone tell me how I can import one Gradle file into another, in a similar manner to Ant's task? I've trawled Gradle's docs to no avail so far.
Additional Info
After Tom's response below, I thought I'd try and clarify exactly what I mean.
Basically I have a Gradle script which runs a number of subprojects. However, the subprojects are all NetBeans projects, and come with their own ant build scripts, so I have tasks in Gradle to call each of these.
My problem is that I have some configuration at the top of the file, such as:
projects = [
[name:"MySubproject1", shortname: "sub1", env:"mainEnv", cvs_module="mod1"],
[name:"MySubproject2", shortname: "sub2", env:"altEnv", cvs_module="mod2"]
]
I then generate tasks such as:
projects.each({
task "checkout_$it.shortname" << {
// Code to for example check module out from cvs using config from 'it'.
}
})
I have many of these sort of task generation snippets, and all of them are generic - they entirely depend on the config in the projects list.
So what I want is a way to put this in a separate script and import it in the following sort of way:
projects = [
[name:"MySubproject1", shortname: "sub1", env:"mainEnv", cvs_module="mod1"],
[name:"MySubproject2", shortname: "sub2", env:"altEnv", cvs_module="mod2"]
]
import("tasks.gradle") // This will import and run the script so that all tasks are generated for the projects given above.
So, in this example, tasks.gradle will have all the generic task generation code in, and will get run for the projects defined in the main build.gradle file. In this way, tasks.gradle is a file that can be used by all large projects that consist of a number of sub-projects with NetBeans ant build files.
There is a new feature in 0.9. You can use apply from: 'other.gradle' command.
Read my question about same thing at: Is there a way to split/factor out common parts of Gradle build
The answer to the question turned out to be in the Plugins system, where you can add the desired functionality in a set of plugins which can be groovy files located in the directory buildSrc/src/main/groovy. Plugins can also be bundled as a Jar though I haven't tried this.
Details here: Custom Plugins
Well, it is hard to tell what serves you best without actually seeing your build file.
I could assume that stetting up your environment as multi-project build should provide you the abstraction you are looking for.
In your project root build.gradle you define all your domain specific stuff as well as the things that apply to all your subprojects:
repositories {
add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
name = 'destRepo'
addIvyPattern( file( project.properties['repo.dest.dir']).absolutePath + '/[organisation]/[module]/ivys/ivy(-[revision]).xml')
addArtifactPattern( file( project.properties['repo.dest.dir']).absolutePath + '/[organisation]/[module]/[type]s/[artifact](-[revision]).[ext]')
descriptor = 'optional'
checkmodified = true
}
...
}
...
subprojects {
sourceCompatibility = 1.5
targetCompatibility = 1.5
group = 'my.group'
version = '1.0'
uploadArchives {
uploadDescriptor = true
repositories {
add rootProject.repositories.destRepo
}
}
apply{ type my.group.gradle.api.plugins.MyPlugin }
...
}
dependsOnChildren()
The project root directory might also contain a gradle.properties file where you define properties used by your projects:
buildDirName=staging
repo.dest.dir=/var/repo
...
Then in an additional file from your project root named settings.gradle you actually point to your subprojects:
include 'my-first-component',
'my-second-component'
...
project(':my-first-component').projectDir = new File(rootDir, 'path/to/first/component')
project(':my-second-component').projectDir = new File(rootDir, 'path/to/second/component')
...
Each sub-project directory contains a build.gradle file containing the sub-project specific stuff only.
No matter if you invoke gradle from your project root or sub-project directory, gradle will automatically consider all your definitions done in the various files.
Also note that no compile task will be executed for your project root as long as you don't load any plugin beyond the default plugin at the root level.
This is an example for Kotlin DSL (build.gradle.kts).
apply(from = "scripts/my-script.gradle.kts")
scripts/my-script.gradle.kts:
println(
"""
I am defined at the top level of the script and
executed at the configuration phase of build process
"""
)
tasks.create("MyTask") {
println(
"""
I am defined in a task and
run at the configration phase of build process"""
)
doLast {
// ...
}
}
See this answer and this answer for how to import a function from another script in Kotlin DSL.
Based off this similar question/answer, the easiest solution I've found after searching for days is using buildscript.sourceFile. It correctly gives the file being run rather than the pwd/cwd/parent-file of said process. I feel like this would solve your issue.

Categories