How create JAR from upstream Web App as Dependency for downstream Web App - maven

I have (amongst other modules) a NetBeans8.1 Maven web app project CoreWeb that (with other module dependencies resolved) runs standalone fine, and is supposed to under any circumstances at least build its default WAR and run standalone.
I have a 2nd NetBeans8.1 Maven web app project SpecWeb that depends on CoreWeb; it is to reuse both JSF managed beans from CoreWeb and also leverage XHTML composite component JSF resources from CoreWeb.
But on building SpecWeb it does not resolve the CoreWeb dependency, because CoreWeb does not (by default) also build a JAR:
Failed to execute goal on project SpecWeb: Could not resolve dependencies
for project com.example.multi:SpecWeb:war:1.0-SNAPSHOT: Could not find
artifact com.example.multi:CoreWeb:jar:1.0-SNAPSHOT -> [Help 1]
(I had this problem with an Ant version of my project with multiple modules and solved it using a small piece of Ant task script to build the extra JAR from CoreWeb for use in SpecWeb, worked perfectly.)
Q: How can I generate a JAR (as well as the WAR) from CoreWeb for use in SpecWeb ?
Under Project > Actions: Build Project I've tried adding various additional goals to install for the Build Project action (using the NetBeans prompting feature).
Using install jar:jar did not work. It indeed created a JAR (as well as the WAR), but that JAR only included the managed bean classes, not the resources, and on build from the "downstream" SpecWeb it still failed to find it:
$ jar tf target/CoreWeb-1.0-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/multi/
.. Java managed bean classes ..
META-INF/maven/
META-INF/maven/com.example.multi/
META-INF/maven/com.example.multi/CoreWeb/
META-INF/maven/com.example.multi/CoreWeb/pom.xml
META-INF/maven/com.example.multi/CoreWeb/pom.properties
I get the same JAR structure built (without JSF XHTML composite component web resources) if I manually change the packaging in the pom.xml to jar:
<groupId>com.example.multi</groupId>
<artifactId>CoreWeb</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!--
<packaging>war</packaging>
-->
EDIT: Overlays also not working (in NetBeans)
I have also tried using Overlays, but it's not working as expected. As soon
as I turn the dependency into type war NetBeans can't resolve classes from CoreWeb imported into classes from SpecWeb, and it won't even compile (and the class files have NetBeans Java warnings because of the failed import):
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
Also, as soon I enter <type>war</type> the CoreWeb project vanishes from the list under the project navigator node SpecWeb > Dependencies.
Also tried Warpath plugin
NetBeans still does not see classes in CoreWeb imported into classes in SpecWeb, so SpecWeb won't compile.

After lot of research (mostly on the main Maven site) and trial and error, I have found a robust solution compatible with NetBeans.
A general description of the strategy. The trick is to create an additional "client" JAR version of the CoreWeb project for temporary use by the SpecWeb project (enabling NetBeans editor to "see" the classes of CoreWeb), and declare it as an additional dependency of only 'provided' scope (so it does not make it into the final SpecWeb WAR). Then also use overlays to combine both the composite components of CoreWeb and the managed beans of CoreWeb with the SpecWeb project into the final WAR, being careful to exclude the index.xhtml from CoreWeb.
Steps
In the pom.xml from CoreWeb include this:
<!-- Also make JAR form using classifier during package phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>client</classifier>
</configuration>
</execution>
</executions>
</plugin>
On build this will create:
$ ls -1 CoreWeb/target/CoreW*
CoreWeb/target/CoreWeb-1.0-SNAPSHOT-client.jar
CoreWeb/target/CoreWeb-1.0-SNAPSHOT.war
CoreWeb/target/CoreWeb-1.0-SNAPSHOT:
META-INF/
WEB-INF/
index.xhtml
resources/
(Note NetBeans can run CoreWeb independently directly over CoreWeb/target/CoreWeb-1.0-SNAPSHOT with its own index.xhtml.)
SpecWeb can then use CoreWeb-1.0-SNAPSHOT-client.jar thus in its pom.xml:
<dependencies>
...
<!-- This is needed for the editor and for the compilation only (not at runtime) -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<version>${project.version}</version>
<type>jar</type>
<classifier>client</classifier>
<scope>provided</scope> <!-- To prevent being written even to target folder -->
</dependency>
<!-- This is needed for the overlay -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
Note how there are 2 separate types of dependency of SpecWeb on CoreWeb:
A dependency on the CoreWeb-1.0-SNAPSHOT-client.jar using the classifier client and with scope runtime (so it won't be included under /target at all). This will appear in the NetBeans project window under a special node Non-Path Dependencies, with a clear indication that it is for [runtime] only.
A dependency on the CoreWeb-1.0-SNAPSHOT.war for the overlay to use. This will appear in the NetBeans project window under the node Dependencies.
Then also in the pom.xml for SpecWeb specify the overlays (excluding the CoreWeb's index.html) and packaging (to be sure also excluding any "client" jars):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>WEB-INF/lib/*-client.jar</packagingExcludes>
<overlays>
<overlay>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<excludes>
<exclude>index.xhtml</exclude>
</excludes>
</overlay>
<overlay>
<!-- empty groupId/artifactId represents the current build -->
</overlay>
</overlays>
</configuration>
</plugin>
The SpecWeb project behaves correctly in the NetBeans editor (classes from CoreWeb are seen), compiles ok, and can be run over SpecWeb/target/SpecWeb-1.0-SNAPSHOT with its own index.html, with access to both the JSF managed beans and JSF composite components of CoreWeb.
CAVEAT: NetBeans XHTML editor will complain when editing JSF pages from SpecWeb that the composite components provided by CoreWeb don't exist because of this known NetBeans Bug 257684 - JSF 2 composite components in JAR are not recognized , but the project will still run ok.

Related

Exclude Java package from dependency jar

I want to use jar from third party vendor. But in this jar I have old version of Java package org.osgi.framework I need to find some way to exclude the package from the main project. Something like this:
<dependency>
<groupId>com.ibm</groupId>
<artifactId>com.ibm.ws.admin.client</artifactId>
<version>8.5.0</version>
<exclusions>
<exclusion>org.osgi.framework</exclusion>
</exclusions>
<type>jar</type>
</dependency>
Can you recommend some solution?
Although a better solution would be to re-pack the dependency (without the unwanted package) with a classifier (as described in this answer) and publish it on your enterprise Maven repository (or install it into your local Maven cache, if it's a personal project), below is a different solution which should also suit your needs.
You could have a multi-module Maven project, having a module with just this dependency and in it you could use the Maven Shade Plugin and its filters property as explained in its official example.
As per documentation, the filters element:
Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by artifactSet and a set of include/exclude file patterns for filtering which contents of the archive are added to the shaded jar
In your case, the following configuration should apply the filter:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>com.ibm:com.ibm.ws.admin.client</artifact>
<excludes>
<exclude>org/osgi/framework/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The generated jar from the package phase should not contain that package any longer. As part of the Maven output you should see:
[INFO] --- maven-shade-plugin:2.4.3:shade (default) # test-checksum ---
[INFO] Including com.ibm:com.ibm.ws.admin.client:jar:8.5.0 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
You can verify the content of the generated jar, the filtered package should not be there.
Then, the output of this module will have the "new"/filtered jar you were looking for. Then the consumer module would just need to have a dependency on this module and as such have the filter applied.
An example of such a multimodule project would be:
+ aggregator/parent project
- filtered-dependency-module (applying the shade filter)
- consumer-module (having dependency on the filtered module)
Update
Further note: in the module which applies the filter, you should declare the dependency as optional so that the consumer module doesn't bring it in transitively again.
<dependencies>
<dependency>
<groupId>com.ibm</groupId>
<artifactId>com.ibm.ws.admin.client</artifactId>
<version>8.5.0</version>
<optional>true</optional>
</dependency>
</dependencies>
Optional doesn't affect the module itself, only the consumer one. And the Shade plugin will keep on working (I re-tested it, just in case).

How to create additional jar file with contents of all modules during maven build?

I have a multi-module maven project (say project-xxx). Lets say it consists of 5 modules:
project-xxx (war)
--> module-1 (jar)
--> module-2 (jar)
--> module-3 (jar)
--> module-4 (jar)
--> module-5 (jar)
When the maven project is built, the war file is generated and it includes the jar files of the 5 modules as well.
Now, for a different purpose (i.e., deploy to a distributed cache, so we can run queries from command-line), I want to generate a single `jar' file as well which includes the java classes from all modules. I'm aware that it is against maven's philosophy to generate more than one artifact and I read this blog post and a few other questions on SO.
But creating this single jar file would greatly simplify a few other things in my project. What would be the best approach to go about generating this single jar file?
I am very much in favor of the one artifact per Maven project convention. That being said, if you need a single artifact that contains all of the classes for all of the modules, then make a dedicated single project to do so:
<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>
<groupId>your-group-id</groupId>
<artifactId>one-jar-to-rule-them-all</artifactId>
<version>your-version</version>
<dependencies>
<dependency>
<groupId>your-group-id</groupId>
<artifactId>module-1</artifactId>
<version>your-version</version>
</dependency>
.
.
.
<dependency>
<groupId>your-group-id</groupId>
<artifactId>module-5</artifactId>
<version>your-version</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<!--
This restricts the jar to classes from your group;
you may or may not want to do this.
-->
<artifactSet>
<includes>
<include>your-group-id</include>
</includes>
</artifactSet>
<createDependencyReducedPom>true</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This example project depends on each module and then uses the maven-shade-plugin to combine all of those modules together into a single jar artifact. You could also make this a child module of your parent project-xxx so it gets built by the reactor. This way, you can have both a war and an uber jar, but still keep the modularity of a standard Maven build.
I think you should consider introducing first separate profiles, so that profile1 would contain the configuration to result a proper war packaging. Profile2 could contain configuration using the maven-shade-plugin, in order to create an UBER jar out of your existing modules. Profiles are a very clean and maven-ish way to split different concerns.
For maven profiles see here. For the maven-shade-plugin see here.
Hope that helps.

How to include resources from war to another maven project

I have a maven project , which needs to copy webapp/WEB-INF/ resources from another maven project which is packaged as a war .
How do I do it ?
PLease suggest
As Bittrance said, you should use the maven dependency plugin.
The better way is to create project that include all your shared resources, probably a type zip, which is build up with the assembly plugin. This is the good "maven way". It's a better solution than unpacking a war.
Then, refer it
<dependency>
<groupId>com.mygroup/groupId>
<artifactId>my-dependencies</artifactId>
<version>1.0.0</version>
<type>zip</type>
</dependency>
Next, you use the maven dependency plugin to unpack your resources, in the directory of your choice (probably WEB-INF/ ?)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-cfg-test-resources</id>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<phase>resources</phase>
<configuration>
<outputDirectory>${project.build.directory}/WEB-INF/</outputDirectory>
<includeArtifacIds>my-resources</includeArtifacIds>
<excludeTypes>pom</excludeTypes>
<excludeTransitive>true</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
I'm not realy sure of this code snippet (written for another purpose), but this is an example.
For more information, please follow this link : http://maven.apache.org/plugins/maven-dependency-plugin/
If you can't shared a common-project including your files, you can unpack war including only ftl (or whatever you want), but it's not a realy clean solution ;)
There is a lot of posts that deal with this subject :
Unzip dependency in maven
...
Just try with the keywords maven-dependency-plugin, unpack :)
Hope that will help you.
I can see some alternatives:
Use external references in your version control system to point all repos to the same files.
The Maven Dependency module can copy and unpack project dependencies. From there, you can use the Maven Assembly plugin (or Ant targets) to include parts of that dependency in your own installation.
At least for the FTL files, perhaps you could package them in a separate Jar file and then load them as resources through the class loader.
If the resources are filtered, you may get into problem with solution 1 if you want the filtered version and 2, 3 if you want the source version.
Hope this helps.
(This assumes your dependent project is java (jar) and not another web app, if it is a webapp I think the solution is similar).
I suggest a (slightly) different approach:
Instead of reading resources from war, add this to your war pom, to generate a jar in the artifact as well as a war:
<!-- maven war plugin config -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<configuration>
...
<attachClasses>true</attachClasses>
<classesClassifier>some-string</classesClassifier>
</configuration>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
...
<resources>
<!-- This is for inclusion in the jar, so dependent module can load it -->
<resource>
<targetPath>some-path</targetPath>
<directory>src/main/webapp/path...</directory>
<includes>
<include>your-resource</include>
</includes>
</resource>
</resources>
And this to your consuming pom, so the generated jar will be loaded:
<dependency>
<groupId>com.company</groupId>
<artifactId>...</artifactId>
<classifier>some-string</classifier>
</dependency>
Then you will be able to load the resources the usual way (getResourceAsStream("some-path/your-resource"))

General Maven bugginess

So I'm finding that the more I use Maven, the buggier I'm finding it to be, especially when building the same project using different Maven versions. Is this to be expected?
A couple of examples:
I have a .ear I'm deploying to JBoss. As I'm bringing in wsdls, xsds and generated classes brought in on the class path, I'm bring the .jar in as a dependency then unpacking it into the .ear. To do this I'm using the unpack dependencies goal. Looks something like this...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>unpack-wsimport</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>url.projectName</includeGroupIds>
<includeArtifactIds>projectName-wsimport</includeArtifactIds>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Using Maven 3.0.3 (Which is what the project was originally built in), this works fine. Switch over to Maven 2.0.9 and all of a sudden it doesn't. On the Maven site it says this plugin has been supported since version 1.0, so why isn't it working?
In the same vein, but vice versa, when I'm trying to do a maven release of this project, using Maven 2.0.9 will prepare and perform correctly, however 3.0.3 doesn't copy across certain files when tagging a version in SVN.
Anyone else finding errors like this when switching between versions of Maven to build projects?
First it looks like you didn't understand the maven way of doing things like an ear, cause within a EAR you have to add the dependencies which should be put into the EAR not via the dependency-plugin you have to use them as dependencies instead.
for Example:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.6</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>webgui</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>service</artifactId>
<version>${project.version}</version>
<type>ejb</type>
</dependency>
</dependencies>
but the better approach is to use the correct configuration for the maven-ear-plugin.
Based on the information you gave i would have expected to have a multi-module build which contains your different modules (like web-part, wsdl-part etc.) which will be packaged into an EAR. This would have resulted into a structure like the following:
+-- root
+-- pom.xml
+-- war
+-- pom.xml
+-- wsdl
+-- pom.xml
+-- ...
+-- ejb
+-- pom.xml
+-- ear
+-- pom.xml
Furthermore it looks like you need to look into the orginization of projects like multi-module projects. Here is an example of such kind. The documentation about Maven is a good way to start with and last but not least Maven by Example.
About your point of buggines i can't acknowledge this, cause i'm working a long time with Maven in really large project (100 modules +)...Furthermore i would like to know where it's stated that this plugin works with version 1.0.
Despite the fact that it doesn't looke like that you read the release notes. There is large number of differences between the Maven versions in particular between Maven 2.0.X, 2.2.X and 3.0.X ..If you really need to run your build with differernt Maven version like 2.0, 2.2, and 3.0. This can be done and is working, but there are some drawbacks based on the technical detail in particular between 2.2.X and 3.0.X (reporting are). I would suggest to use only one Maven version to build your artifacts (currently 3.0.3/3.0.4). An other hint is that a Maven build which works for Maven 2/3 never will run with Maven 1, cause the POM has been changed dramatically.

Maven WAR dependency

I am writing a project for acceptance testing and for various reasons this is dependent on another project which is packaged as a WAR. I have managed to unpack the WAR using the maven-dependency-plugin, but I cannot get my project to include the unpacked WEB-INF/lib/*.jar and WEB-INF/classes/* to be included on the classpath so the build fails. Is there a way to include these files into the classpath, or is there a better way of depending on a WAR?
Many thanks.
There's another option since maven-war-plugin 2.1-alpha-2. In your WAR project:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
This creates a classes artifact which you can use in the acceptance tests project with:
<dependency>
<groupId>your-group-id</groupId>
<artifactId>your-artifact-id</artifactId>
<version>your-version</version>
<classifier>classes</classifier>
</dependency>
Indeed, by design, Maven doesn't resolve transitive dependencies of a war declared as dependency of a project. There is actually an issue about that, MNG-1991, but it won't be solved in Maven 2.x and I'm not sure that I don't know if overlays allow to workaround this issue. My understanding of the suggested solution is to duplicate the dependencies, for example in a project of type pom.
(EDIT: After some more digging, I found something interesting in this thread that I'm quoting below:
I have been helping out with the development of the AppFuse project over
the last month where we make heavy use of the war overlay feature in the
Maven war plugin. It is a really nifty feature!
To get max power with war overlays I have developed the Warpath plugin
that allows projects to use war artifacts as fully fledged dependencies.
In brief:
1) The contents of the /WEB-INF/classes directory in the war dependency
artifacts can be included in the project's classpath for normal compile,
etc tasks.
2) Transitive dependencies from the war dependency artifacts become
available for use by other plugins, e.g. compile and ear - so no more
having to include all the dependencies when creating skinny wars!
The plugin has now been actively used in the AppFuse project for the
last few months, and I feel it is at a point where it is both usable and
stable.
Would the war plugin team be interested in including the warpath
functionality inside the war plugin? It would seem to be the most
natural place to host it.
So, I don't have any experience with it, but the maven warpath plugin actually looks nice and simple and is available in the central repo. To use it,include the following plugin configuration element in your pom.xml file:
[...]
<build>
<plugins>
<plugin>
<groupId>org.appfuse</groupId>
<artifactId>maven-warpath-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>add-classes</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
And add the war dependencies you want included in the classpath as warpath type dependencies:
[...]
<dependencies>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>warpath</type>
</dependency>
</dependencies>
[...]
Both the war and warpath dependency types are needed: the war type is used by the Maven war plugin to do the war overlay, the warpath type is used by the Warpath plugin to determine the correct list of artifacts for inclusion in the project classpath.
I'd give it a try.)
Use overlays. First, your test project need to have also packaging war.
Declare dependency of war project you want to test:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>your-project-arftifactId</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
then configure maven-war-plugin overlay:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/webresources</directory>
<filtering>true</filtering>
</resource>
</webResources>
<overlays>
<overlay/>
<overlay>
<groupId>your.group</groupId>
<artifactId>your-project-artifactId</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
In the above example in test project I overwrite webresources configuration files (like conxtext etc.).
EDIT: This solution wasn't tested with Maven 3.
Good point, Justin. That got me actually solving my problem, namely: including a war into an assembly AND including all its transitive dependencies.
I could not duplicate the war-dependency as 'jar' as you suggested since the assembly plugin would not find a jar referenced by that groupId/artefactId, but
duplicating the war-dependency as type pom
works!
The war and its transitive dependencies are not included in the assembly.
To exclude the (now also appearing) pom file I had to add an exclude element like this:
<excludes>
<exclude>*:pom</exclude>
</excludes>
into my assembly.xml file.
I think this could also be a workaround for the original question of this thread.
If you list the dependency on the war project as a jar dependency it seems to pickup the required jars/resources. I'm using Maven 2.2 + m2eclipse.

Resources