I mentioned this in one of the earlier posts:
But maven makes creation of such an EAR hmmm ... interesting. I just hate to think what amount of work I would need to do if I needed some dependencies in EAR/lib and some in WEB-INF/lib and most importantly what amount of work would it be to maintain this structure.
The time has come. I need some jars in WEB-INF/lib (tag libraries) and the rest in <EAR>/lib. So let's look at "convention over configuration" a little bit closer. This is what I have to do:
- WAR's pom.xml: declare dependencies on external jars and on some other subprojects (couple of EJBs), nothing unusual, should be done anyway. I mention it here for completeness.
- EAR's pom.xml: again, nothing unusual, declare dependency on EJB en WAR projects.
Sorry, got carried away. Ah, dreams, dreams...
Reality is quite different. Sure, if I do what I just mentioned, the resulting WAR file is correct. But EAR is completely screwed up because the WAR is included "as is". Some dependency jars are present in <EAR>/lib and in <WAR>/WEB-INF/lib. All EJB jars are also present twice, in <WAR>/WEB-INF/lib and in the root of EAR.
Maven offers some ... hmmm ... solution for the problem, documented here: "Solving the Skinny Wars problem". They honestly warn you saying:
The Maven WAR and EAR Plugins do not directly support this mode of operation but we can fake it through some POM and configuration magic.
Let's look at their "configuration magic". It is consists of 2 pieces of configuration that has to be applied to WAR and EAR pom files:
- You have to configure WAR pom.xml to remove jars from WEB-INF/lib and to add their names in MANIFEST.MF. Note that these options are orthogonal and you have to specify both.
And if you need to leave some of the jars in WEB-INF/lib (I need to), then the configuration becomes really crazy. Watch the "POM and configuration magic":- option 1:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingExcludes>
WEB-INF/lib/C*.jar,
WEB-INF/lib/R*.jar,
WEB-INF/lib/a*.jar,
WEB-INF/lib/b*.jar,
WEB-INF/lib/c*.jar,
WEB-INF/lib/d*.jar,
WEB-INF/lib/e*.jar,
WEB-INF/lib/h*.jar,
WEB-INF/lib/jb*.jar,
WEB-INF/lib/js*.jar,
WEB-INF/lib/joda-time-1*.jar,
WEB-INF/lib/joda-time-h*.jar,
WEB-INF/lib/sl*.jar
</packagingExcludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin> - option 2:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingIncludes>
WEB-INF/lib/standard-1.1.2.jar,
WEB-INF/lib/joda-time-jsptags-1.0.2.jar,
**/*.xml,
public/**/*.*,
images/**/*.*,
css/**/*.*
static/**/*.*
</packagingIncludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
No matter how you look at the problem it is not really "convention". Hell, it is "configuration, configuration, configuration, and even more configuration". And, worst of all, the resulting WAR file cannot be deployed separately, only as part of an EAR. Oops, here go all your nice integration tests. Fortunately it is not a problem for our current project because we do not deploy WAR files separately. But I can imagine some other people would like to do it.
This "solution" has a minor problem that the resulting MANIFEST.MF is also incorrect: it has all jars mentioned in Class-Path: attribute, even those that stay in WAR/WEB-INF/lib.
Oh yeah, and some annoyance: I have to specify exclusion by file name and not by dependency. I have only 4 dependencies in WAR's pom.xml and look at that exclusion list! - option 1:
- But it is not all! More "configuration magic": you also have to change EAR's pom.xml and add all WAR-only dependencies that are not included in <WAR>/WEB-INF/lib. Otherwise they are not packaged into EAR/lib. Lucky you, it is WAR-only dependencies, and not dependencies of EJBs.
This is of course not new. The related bug MWAR-9 has just turned 5 years. Congratulations, maven! Happy anniversary, MWAR-9!
This post was brought to you by maven notion of convention over configuration.
There is other solution to exclude specific jar from lib:
ReplyDelete%regex[lib/(?log4j*).*]