DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Retrieval Augmented Generation With Spring AI 2.0, Claude, and PGvector
  • Fix Circular Dependencies in PostgreSQL Row-Level Security With SECURITY DEFINER Functions
  • Sharing SBOMs Securely Without Giving Too Much Away
  • Securing CI/CD Pipelines Against Supply Chain Attacks: Why Artifacts and Dependencies Matter More Than Ever

Trending

  • Idempotency Under Concurrency: Why Your Application Check Isn't the Last Line of Defense
  • Member Spotlight: Srinivas Chippagiri
  • Spring Security JWT Validation Best Practices
  • How to Evaluate Coding Agents With Harbor Framework, Python, Docker

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Software Design and Architecture
  3. Security
  4. DRY and Skinny War

DRY and Skinny War

By 
Nicolas Fränkel
·
Apr. 27, 10 · Interview
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
14.8K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

In this article, I will show you how the DRY principle can be applied when using the skinny war configuration of the maven-war-plugin.

While packaging an EAR, it is sometimes suitable that all libraries of the different WARs be contained not in their respective WEB-INF/lib folders but at the EAR level so they are usable by all WARs. Some organizations even enforce this rule so that this is not merely desiarable but mandatory.

Using Maven, nothing could be simpler. The maven-war-plugin documents such a use case and calls it skinny war. Briefly, you have two actions to take:

  • you have to configure every WAR POM so that the artifact will not include any library like so:
    <project>
    ...
    <build>
    <plugins>
    <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
    <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
    <archive>
    <manifest>
    <addClasspath>true</addClasspath>
    <classpathPrefix>lib/</classpathPrefix>
    </manifest>
    </archive>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </project>
  • you have to add every dependency of all you WARs in the EAR

The last action is the real nuisance since you have to do it manually. In the course of the project, a desynchronization is sure to happen as you add/remove dependencies from the WAR(s) and forget to repeat the action on the EAR. The DRY principle should be applied here, the problem lies in how to realize it.

There's an easy solution to this problem: if a POM could regroup all my WAR dependencies, I would only have to draw a dependency from the WAR to it, and another from the EAR to it and it would fulfill my DRY requirement. Let’s do it!

The pomlib itself

Like I said before, the pomlib is just a project whose packaging is POM and that happens to have dependencies. To be simple, our only dependency will be Log4J 1.2.12 (so as not have transitive dependency, let’s keep it simple).

The POM will be:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.frankel.blog.pomlib</groupId>
<artifactId>pomlib-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>pomlib-lib</artifactId>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
</project>

Like for any other project module, I put the versions in the parent POM.

The EAR and the WAR

Both should now add a dependency to the pomlib. For brevity, only the EAR POM is displayed, the WAR POM can be found in the sources if the need be.

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.frankel.blog.pomlib</groupId>
<artifactId>pomlib-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>pomlib-ear</artifactId>
<packaging>ear</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>pomlib-lib</artifactId>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>pomlib-war</artifactId>
<type>war</type>
</dependency>
</dependencies>
</project>

Likewise, versions are put in the parent POM. Notice the import scope on the pomlib dependency, it’s the only magic.

Using mvn install from this point on will put the log4j dependency at the root of the generated EAR artifact and not in the WEB-INF/lib folder of the WAR.

Conclusion

Now that all dependencies are described in the pomlib, should you need to add/remove a dependency, it’s the only place you’ll need to modify. With just a little configuration, you’ve streamlined you delivery process and saved yourself from a huge amount of stress in the future.

By the way, if you use a simple Servlet container (like Tomcat or Jetty) as your development application server, you could even put the skinny war configuration in a profile. Maven will produce “fat” WARs by default, at development time. At delivery time, just activate the profile and here’s your EAR product, bundling skinny WARs.

You can find the source of this article in Maven/Eclipse format here.

 

From http://blog.frankel.ch/dry-and-skinny-war

WAR (file format) Dependency EAR (file format)

Opinions expressed by DZone contributors are their own.

Related

  • Retrieval Augmented Generation With Spring AI 2.0, Claude, and PGvector
  • Fix Circular Dependencies in PostgreSQL Row-Level Security With SECURITY DEFINER Functions
  • Sharing SBOMs Securely Without Giving Too Much Away
  • Securing CI/CD Pipelines Against Supply Chain Attacks: Why Artifacts and Dependencies Matter More Than Ever

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook