Please bear with the long post as I want to put as much details as I can to get the right help.
I am using Java8, Eclipse Photon, Gradle 5.2 and Tomcat 8.5 as my development environment.
We have a legacy web app with Ant
Build which I am trying to switch on to Gradle
.
I started with a multi-project setup where my root project MyRootProj
contains the following settings.gradle
and build.gradle
// MyRootProj build.gradle
allprojects {
repositories {
mavenCentral()
}
apply plugin : 'eclipse-wtp'
apply plugin : 'java'
}
configure(subprojects.findAll {it.name != 'MyWebProj'}) {
dependencies {
// dependencies common to all projects go here
testImplementation 'junit:junit:4.12'
}
sourceSets {
main {
java {
srcDirs 'src'
}
resources {
srcDirs 'src'
}
}
test {
java {
srcDirs 'test'
}
resources {
srcDirs 'test'
}
}
}
}
and settings.gradle
// MyRootProj settings.gradle
rootProject.name = 'MyApp'
include ':JavaProjA', ':JavaProjB', ':JavaProjC', ':MyWebProj'
JavaProjB
is dependent on JavaProjA
and JavaProjC
is dependent on both JavaProjA
and JavaProjB
.
Individual build.gradle
for all four projects are as below:
// JavaProjA build.gradle
dependencies {
// all dependencies for this project go here
implementation 'com.google.guava:guava:19.0'
}
for JavaProjB
// JavaProjB build.gradle
dependencies {
// all dependencies for this project go here
implementation project(:JavaProjA)
implementation 'org.apache.poi:poi:3.10-FINAL'
}
for JavaProjC
// JavaProjC build.gradle
dependencies {
// all dependencies for this project go here
implementation project(:JavaProjA)
implementation project(:JavaProjB)
implementation 'org.apache.commons:commons-lang3:3.3.2'
}
And finally for MyWebProj
// MyWebProj build.gradle
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
war {
baseName = 'MyApp'
webAppDirName = 'src/webapp'
}
// copying required files
tasks.war.dependsOn(/* task to copy required jsp, html, etc. in src/webapp */)
dependencies {
implementation project(:JavaProjA)
implementation project(:JavaProjB)
implementation project(:JavaProjC)
}
// Stop eclipse tying to find java source in web project.
sourceSets {
main {
java.srcDirs = []
}
}
eclipse {
wtp {
facet {
facet name: "jst.web", version: "2.5" // Legacy app. Can't upgrade
}
}
}
At this point I identified two issues and did the following to resolve them:
Issue 1: When I import MyRootProj
in Eclipse, I get duplicates on file search. As Eclipse loads all project under MyRootProj
as well as all projects as independent projects as well.
To resolve this, I moved to includeFlat
. So under a MyRootDir
, I now have MyRootProj
as a sibling project alongside JavaProjA
, JavaProjB
, JavaProjC
and MyWebProj
.
So MyRootProj's
settings.gradle
has this line now:
includeFlat 'JavaProjA', 'JavaProjB', 'JavaProjC', 'MyWebProj' // note the absence of : colon
Everything else stayed the same.
Issue 2: Since the implementation lines for JavaProjA
were getting duplicated in JavaProjC
and MyWebProj
and line for JavaProjB
in JavaProjC
and MyWebProj
. I switched from java
plugin to java-library
plugin so that I can use api
.
So allProjects
block of MyRootProj's
build.gradle
now has this line:
apply plugin : 'java-library' // instead of java to use api
And the dependency lines in JavaProjB
, JavaProjC
and MyWebProj
got changed to:
api project(':JavaProjA') // in JavaProjB's build.gradle
and
api project(':JavaProjB') // in JavaProjC's build.gradle
and
api project(':JavaProjC') // in MyWebProj's build.gradle
All other external dependencies (like apache commons, and google guava) stayed as implementation
So this is my setup right now:
-
includeFlat
structure -
java-library
plugin for using api -
war
andeclipse-wtp
(along withjava-library
throughallProjects
block) plugin in Web Project.
Now my eclipse has latest version of BuildShip
installed.
Buildship: Eclipse Plug-ins for Gradle
3.0.1.v20181217-1547
org.eclipse.buildship.feature.group
Eclipse Buildship
At this point, when I import MyRootProj
in eclipse as a Gradle Project
; it nicely imports JavaProjA
, JavaProjB
, JavaProjC
, MyWebProj
as well alongside MyRootProj
.
Duplicates in file search are all gone and build task runs successfully for all projects resulting in a WAR file, which if I drop it directly in Tomcat's
webapp
directory outside Eclipse
and run Tomcat
from windows services, runs as expected.
However, our development is all on Eclipse
and thus it would be nice if I can run my application in the Tomcat
through Eclipse's
Server
tab. It would also be great if hot deploy can be enabled so that any change to a file in any of the project, automatically gets reflected inside the running app in Tomcat
.
But that’s not happening. When I right click on Tomcat
on Server
tab and do Add and Remove
and add MyWebProj
and start Tomcat
, I see a directory MyWebProj
getting created inside wtpwebapps
folder of Tomcat
directory and it has all the files copied correctly through the tasks.war.dependsOn
. But I do not see WEB-INF/lib
. And thus the web startup fails complaining about missing classes.
I found the following link https://github.com/gradle/gradle/issues/6341 which shows a workaround to solve this.
So I added the following ONLY IN my MyWebProj's
build.gradle
:
eclipse {
wtp {
component {
libConfigurations += [ configurations.runtimeClasspath ]
}
}
}
However, that is not making any difference. I still can not run my app and can not see WEB-INF/lib
in wtpwebapps
At this point I am stuck and do not know the reason for this happening and would really appreciate any guidance for the same. I am new to Gradle
, thus not sure what could be the issue and why the suggested work around is not working.
- Can it be the flat structure ?
- Can it be the java-library plugin being used instead of java ?
- Am I using the work around incorrectly ?
- Am I doing something else incorrectly ?
My end goal is to make the application run inside eclipse’s tomcat with support of hot deployment for debugging during development.
EDIT 1:
So, the fix shown in that workaround got released today as part of gradle 5.3.1. I upgraded my wrapper to that and every thing started working. I can see WEB-INF/lib now, and my application successfully starts from inside Eclipse’s Tomcat.
The only remaining issue is Hot Deployment.
Say I have my application up and running inside Eclipse on Tomcat which is in Debug Mode.
I add a System.out.println
in a java class inside JavaProjectA
.
This is when weird things starts happening.
- Project jars start getting deleted from
WEB-INF/lib
of my project’s directory insidewtpwebapps
- When I try to add a breakpoint and debug and modify code on the fly when the control is paused on breakpoint, it seems new instances of tomcat are spawned.
- I also get errors about locks on class files.
How do I stabilize hot deploy with the setup described above ?