Eclipse workspace setup and packaging an independent jar - eclipse

I have 5 regular java projects inside an eclipse workspace that have inter-dependencies and external jar-dependencies both
on libraries that exists as maven repositories and libraries that don't.
Everything is working fine inside eclipse but I have two tasks that I need to perform:
1)
Package everything into a runnable jar that I can upload to another computer and run without having to setup
the same eclipse environment there. I've been looking at gradle/maven but don't know if I need something as "complex" as that
and it seems quite alot of my setup has to workspace setup has to change to use those tools, but I may be wrong.
2)
I soon want to host the code of two of the java projects on google code so the workspace should be structured in a way
that makes that task smooth.
I'm mentioning both tasks since I don't know if they interact in some manner.
How do I solve this in a good way?
Thanks in advance.

Your description sounds like a perfect fit for Gradle's multi-project support and it's eclipse and application plug-ins. Here's a quick example of how I would approach it.
Your projects might be in the same eclipse workspace but not necessarily under the same folder, so keep in mind the following directory structure assumes you are free to move them around.
|-- component1
|-- component2
`-- myRunnableApp
The first step is to create your top-level build.gradle file and settings.gradle.
|-- build.gradle
|-- settings.gradle
|-- component1
|-- component2
`-- myRunnableApp
Your settings.gradle will instruct gradle to treat the subdirectories as subprojects.
include ':component1', ':component2', ':myRunnableApp'
Your build.gradle will contain settings that are common to all your subprojects, in this particular case we want to apply the java and eclipse plugins:
subprojects {
apply plugin: 'eclipse'
apply plugin: 'java'
repositories {
mavenCentral()
}
}
This should be enough to get you to generate eclipse projects by issuing gradle eclipse. Next you'll want to declare the dependencies between the projects thusly:
component1/build.gradle
dependencies {
// declare your 3rd party jar dependencies as needed
compile 'group:artifact:version'
}
Now you can declare dependencies between projects - this will be reflected in your eclipse project files when you generate them.
component2/build.gradle
dependencies {
compile project(':component1')
}
And finally, you'll want to apply the applications plugin to your runnable project. It will generate your jar file along with wrapper sh / bat files for unix and windows.
myRunnableApp/build.gradle
apply plugin: 'application'
mainClassName = 'my.custom.app.Main'
dependencies {
// component 1 is a transitive dependency of component 2
compile project(':component2')
}
And that's it! I expect this should be a good starting point for rolling out your own build. Check out the gradle documentation for multi-project builds, the java plugin, the applications plugin and dependency management.
Hope that helps!

Related

Gradle: produced WAR file has two versions of JAR from child project

I have a root project that builds WAR, and two child projects that build JARs. The root project references the child project in this way:
apply plugin: 'war'
jar.enabled = false
war {
dependencies {
runtime project(':application1')
runtime project(':application2')
}
}
application2 depends on application1:
dependencies {
compile '...:application1:1.+'
}
The WAR file includes two versions of application1.jar: one from repository, another just built.
EDIT: Application2 has to depend on application1 as a JAR because that simplifies debugging in Eclipse with embedded Jetty: Eclipse automatically adds application1.jar to classpath of Jetty server launch configuration.
You have specified dependency on application1 project differently for the root project and for the application2.
For your application2 it was made as dependency on a library within some repository, but your root project depends on it as on a subproject. Gradle can't determine, that some library in the repo is the same, as subproject's artifact.
If you don't want to get 2 versions of the same lib, you have to make it dependent from the same library: either as
compile '...:application1:1.+'
or as
runtime project(':application1')
Anyway, it seems to be prefferable, to make it depending on the same subproject in both cases, rather then on some project and on the library in repo.

Gradle Eclipse not working correctly for subprojects

Gradle 2.4 and Eclipse Mars here. Here's my project directory structure:
myapp/ <-- root project
myapp-client/
src/main/groovy/*
build.gradle <-- just declares some client-specific deps
myapp-shared/
src/main/groovy/*
build.gradle <-- shared-specific deps
myapp-server/
src/main/groovy/*
build.gradle <-- server-specific deps and how to package server JAR
build.gradle
settings.gradle
Where myapp/build.gradle is:
allprojects {
apply plugin: 'groovy'
apply plugin: 'eclipse'
apply plugin: 'maven'
apply plugin: 'codenarc'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
repositories {
// ...etc.
}
dependencies {
// ...etc.
}
task wrapper(type: Wrapper) {
gradleVersion = '2.4'
}
}
And where myapp/settings.gradle is:
include ':myapp-shared'
include ':myapp-client'
include ':myapp-server'
When I do a ./gradlew eclipse I get messages indicating that the command was successful. I then open Eclipse to import myapp as a series of individual subprojects.
Expectation based on what I'm used to seeing, historically
In previous projects that contained subprojects, I would go to Import >> Existing Projects into Workspace, where I would see this dialog:
I would then click Browse and select the project root (in this particular case, myapp). Eclipse would then auto-detect the 3 subprojects and populate them as a checked list inside the Projects component in the UI above. I would then click "Finish" and Eclipse would load the 3 subprojects into my workspace, each showing as a separate project (as it should).
What's actually happening
Instead, when I click on myapp as the root project, Eclipse just populates it as a single project, almost as if it doesn't detect that I have subprojects at all:
When I click Finish it imports a single project into my workspace, that has source folders for each of the 3 subprojects. And while that's just an annoyance, the real problem is that the classpath seems to be totally jacked up. For instance, I can add a class to myapp-shared, and then include it in a class defined inside myapp-client, and Eclipse doesn't force me to add an import statement into the client class! It's like the whole project is sharing the same package/namespace.
Can any Gradle gurus spot a defect in my Gradle setup that could be the cause of this?
This was nasty, but I figured it out. Posting the solution here in case anybody else runs into this.
Instead of a single allprojects closure, you need allprojects and subprojects closures. Not sure what is "safe" to put in either closure, but I got this working by simply declaring my repositories inside of allprojects and then putting everything else inside subprojects.
The problem was that I had previously ran gradle eclipse on the root project (before I added in the subprojects closure), and so Gradle generated the typical artifacts (e.g. .projects, .classpath, .settings/*) in the parent/root project directory. So...
Delete Gradle-Eclipse artifacts out of the root directory. Delete the project from your Eclipse workspace (but not the disk!!!). I'd even go so far as to restart Eclipse to clear out any caches if they exist.
Run gradle clean for good measure. Probably not needed.
Run gradle eclipse again.
Re-import into Eclipse, and all will be well in your kingdom once again, my friend.

Gradle dependency sources not appearing in Eclipse for the War Plugin

I am working on a Java web project that uses Gradle (version 2.1) as the build dependency tool. I use Eclipse Luna as my IDE. My OS is Mac 10.9 (Mavericks).
This is my build.gradle file (very basic and stripped down for ease of illustration):
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
sourceCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.google.inject', name: 'guice', version: '3.0'
}
So just one dependency, Guice. I will generate my Eclipse classpath and project files using gradle cleanEclipse eclipse. Then I will import an existing project into my workspace. I like being able to view the source code of my dependencies in my Eclipse projects, so I will open a Guice class, such as com.google.inject.Injector, using CMD-SHIFT-T. And voila, the source code of that file will appear.
But I working on a web project, so I need to be able to build a WAR file instead of a JAR file. Therefore, I am going to apply the Gradle War Plugin by replacing apply plugin: 'java' with apply plugin: 'war'. Then I rerun gradle cleanEclipse eclipse and reopen my project.
Now, instead of seeing the source code when I open up Injector, I will see the bytecode viewer with the Attach Source button. Anyone have any ideas whether it's something I'm forgetting in my build.gradle file or if it could be a bug in Gradle/Eclipse?
Note that I am not using the Gradle Integration for Eclipse Plugin because I wish to pinpoint the root cause of this issue without adding an extra layer of complexity to it. I have also checked other SOF questions about Attach Source issue with Gradle and Eclispe, such as how to tell gradle to download all the source jars and Why is Eclipse not attaching 3rd party libs source files to a WTP-faceted Gradle project?, but to no avail.

Writing a buildSrc Gradle plugin that can be published

I'm writing a custom Gradle plugin for my company to assist with integration tests of our product. My team wants to have the plugin be built with and used in the main product build (like a 'buildSrc' plugin would), but also need the plugin to be published as an artifact for other teams to use in integration with our product.
If I try and include it as a standalone plugin in the settings.gradle file and then also include it in the buildscript as a dependency, it obviously does not work because the buildscript block is interpreted first.
I also tried running another build from within the buildscript like so:
buildscript {
def connection = GradleConnector.newConnector()
.forProjectDirectory(file("${project.projectDir}/theplugin"))
.connect()
try {
connection.newBuild()
.forTasks('clean', 'build', 'install')
.run()
} finally {
connection.close()
}
repositories {
mavenLocal()
...
}
dependencies {
classpath 'com.company.product.gradle.theplugin'
}
}
This causes the plugin to be built and placed in the local Maven repo, but then the initial Gradle build fails directly afterward because it can't resolve the newly built archive. If I run it again, it works. I don't understand this behavior.
I'm probably going down a rabbit hole with this approach. Is there a way to make this work and in a less 'hacky' way?
I discovered a hacky way to accomplish this: symlink the plugins to the buildSrc (on *nix at least).
project directory
project/
buildSrc/ -> gradle_plugins/
gradle_plugins/
pluginA/
pluginB/
...
build.gradle
settings.gradle
...
build.gradle
settings.gradle
project/settings.gradle
include 'gradle_plugins:pluginA'
include 'gradle_plugins:pluginB'
...
project/gradle_plugins/settings.gradle
include 'pluginA'
include 'pluginB'
...
project/gradle_plugins/build.gradle
...
rootProject.dependencies {
runtime project(path)
}
...
The way I'm solving this is the following:
Regular multi project build with buildSrc/myPlugin/.. Within my build process I call ./gradlew -b buildSrc/myPlugin/build.gradle uploadArchives (or whichever task you use to publish your maven artifact).
Due to the "official" hack of having to add the gradle plugin to the runtime dependencies of the root project this step would fail. So I surround it with a try catch. I feel that is not perfect but it seems to work.

Gradle and Eclipse project references

I'm using Gradle with Eclipse and am trying to reference Project1 from Project2 (both under the same root directory), like so:
settings.gradle:
include ':Project1'
project(':Project1').projectDir = new File(settingsDir, '../Project1')
build.gradle
dependencies {
compile project(':Project1')
...}
Project1 is also referenced through the build path. But eclipse/gradle does not recompile and instead uses include the old jar classes. I've also tried to set the plugin to apply plugin: 'eclipse-wtp'.
Just out of curiosity, do you have a block like this somewhere in your build.gradle
eclipse.project {
referencedProjects 'Project1'
}
I ask because, if you don't tell Eclipse that this project references Project1, it won't be included in the build path.