Friday, September 16, 2011

Inheritance in Maven based web projects

Sometimes you want to define a base web project and reuse all web based stuff in all other web projects. This is not rare in big projects. The first thought coming in mind is inheritance. Is there any inheritance between web projects at all? Yes, in a manner of speaking. In Maven based projects there is a nice "overlay" feature for maven-war-plugin. You can point to the base WAR project in the overlay tag and the base project gets extracted bevor it's stuff will be extended or overwritten by inherited project. An example:
<plugin>
    <artifactId>maven-war-plugin</artifactId>
    ...
    <configuration>
        <overlays>
            <overlay>
                <groupId>ip.client</groupId>
                <artifactId>ip-theme-framework</artifactId>
                <classifier>webapp</classifier>
                <excludes>
                    <exclude>META-INF/**</exclude>
                    <exclude>WEB-INF/web.xml</exclude>
                    <exclude>WEB-INF/lib/**</exclude>
                    <exclude>WEB-INF/classes/**</exclude>
                </excludes>
            </overlay>
        </overlays>
    </configuration>
</plugin>
You have also to add a dependency in your inherited project for the base project, of course. Well, this feature works fine, but there is a problem with transitive dependencies. Dependencies defined in the base project are "invisible" for inherited projects. You can not use transitive dependencies, they aren't going to be inherited. And adding of all dependencies again in inherited projects is error-prone and causes some issues during release management. To solve this problem, we can set packaging of all web projects as jar. That's what we do in my company.
<packaging>jar</packaging>
With packaging jar you have still a WAR archive at the end, but Java sources are packed to one jar file which is placed by Maven below WEB-INF/lib inside of the WAR. WEB-INF/classes stays empty. Dependencies get now accepted. One thing to keep in mind: WAR projects with packaging jar should be specified twice as dependencies. Once without <type> and once with <type>war</type>. An example:
<dependency>
    <groupId>ip.client</groupId>
    <artifactId>ip-theme-framework</artifactId>
</dependency>
<dependency>
    <groupId>ip.client</groupId>
    <artifactId>ip-theme-framework</artifactId>
    <classifier>webapp</classifier>
    <type>war</type>
    <scope>runtime</scope>
</dependency>
The last be not least is the support in IDEs. JAR projects are not recognized as web projects in Eclipse, IntelliJ or somewhere else and you lose all goodies from your preferred IDE. A solution is simple and uses profiles. Define a property ${packaging.war} for a special profile (see my last post).
<profile>
    <id>ide</id>
    <properties>
        <packaging.war>war</packaging.war>
    </properties>
</profile>
write variable packaging.war in the packaging tag of your project
<packaging>${packaging.war}</packaging>
and let Maven run with this profile when creating IDE specific files:
mvn -Pide eclipse:eclipse
mvn -Pide idea:idea
...
Summary: Overlays help to reuse web projects. They also help to customize web projects by having one big core project and many small custom specific projects which only have specific CSS, Images (logos, ect.) and messages in property files. Custom specific Maven projects don't have Java classes - the aim is to overwrite / extend resources of core project and achieve a custom Look-&-Feel.

2 comments:

  1. great post, very usefull stuff!!!

    ReplyDelete
  2. Thanks. I have added a summary to this post.

    ReplyDelete

Note: Only a member of this blog may post a comment.