What is the idiomatic approach to a multi-project EAR?

I’m writing up some example builds for internal use and wanted to know what the idiomatic way of setting up a multi-project build (mostly an EAR) is. Most examples I’ve seen use a hierarchical structure:

earProject/
  build.gradle
  settings.gradle
  src/
  warProject/
    build.gradle
    src/

This would involve using

include: 'warProject'

in the settings.gradle. This is a great structure, in general, because you use include vs includeFlat, get the benefits of settings.gradle autodetection from the subproject, etc.

The biggest weakness is that since we use Eclipse, hierarchical projects pose a little bit or a problem, in that it would take two passes to import them (from what I understand).

Most of the testing I have done has been with a flat hierarchy:

earProject/
  build.gradle
  settings.gradle
  src/
warProject/
  build.gradle
  src/

This solves the Eclipse issue, but loses the settings.gradle autodetection from the WAR (unless the EAR project is named master?).

If it was just one project, we could just pick something and refactor later as necessary, but we have a lot of EARs. I’m hoping we can start on as close to the right track as we can get.

You could move settings.gradle up to root. As it only contains includes there is not much need having it available inside Eclipse.

Another option is to upgrade to a superior IDE(A) :wink: …sorry, could not resist.

Hahaha. Idea’s not an option for us at this point.

Moving the settings.gradle to the parent folder works well for general execution. However, now I’m not sure where the best place to inject configuration into other projects is.

It could be done in the normal fashion in the root project. However that would mean having a build.gradle file that exists solely for the purpose of injecting configuration into the subprojects. It would be easy to forget that it was there.

Ideally I’d like to inject dependencies into the WAR’s configuration from the EAR within the EAR’s build.gradle. The most common use case would be injecting the earlib dependencies into the WAR’s providedCompile configuration.

Since the EAR isn’t the rootProject anymore, I run into an issue finding the EAR project due to delegation in the closures. Not an issue in the sense that it doesn’t work, but it seems odd to have to cache the reference to project (or use project(’:ear’) to get at it).

def earProject = project
rootProject.subprojects { subproject ->
  subproject.plugins.withType(WarPlugin) {
    subproject.configurations.providedCompile.dependencies.addAll(earProject.configurations.earlib.dependencies)
  }
}

Not sure that’s the best approach in general… suggestions are welcome.

The biggest weakness is that since we use Eclipse, hierarchical projects pose a little bit or a problem, in that it would take two passes to import them (from what I understand).

From my experience and understanding, the SpringSource Tool Suite Gradle plugin copes just fine with importing hierarchical projects.

My understanding is that the the STS Gradle plugin only handles regular Java projects (maybe Groovy too), but none of the WTP stuff.

Adding some more to Stig’s option, I was able to get the behavior I’m looking for. The settings.gradle which is in an otherwise empty root directory now looks like this:

include 'war'
  rootProject.name = 'ear'
rootProject.projectDir = new File(settingsDir, rootProject.name)

Folder structure is:

root/
  settings.gradle
  ear/
    build.gradle
    ...
  war/
    build.gradle
    ...
  • ear project has all of the benefits of being the root project (use of subprojects { }, etc) * settings.gradle is autodetected when executing from within war folder * still imports fine into eclipse

Now my dillemma is whether this should be the approach we adopt for all of our EARs. Maybe it’s a use whatever works situation, but where do you guys stand on the best approach?