I am trying to exclude a single library .JAR file from my EAR that is being built via Maven, as this library is included as a JBoss EAP module. I've followed the instructions in the documentation, but I always see this library included anyway. Here's what the relevant pom.xml section looks like:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9</version>
<configuration>
<!-- Tell Maven we are using Java EE 6 -->
<version>6</version>
<finalName>MenuProject</finalName>
<!-- Use Java EE ear libraries as needed. Java EE ear libraries are
in easy way to package any libraries needed in the ear, and automatically
have any modules (EJB-JARs and WARs) use them -->
<defaultLibBundleDir>lib</defaultLibBundleDir>
<packagingExcludes>**/postgresql*.jar</packagingExcludes>
<modules>
<!-- Register our War as a web module, and set the context root -->
<webModule>
...
As you see, I'm trying to exclude the postgresql*.jar file from being included in my EAR file. But, when I do a build I still see it.
Am I misunderstanding this functionality? Or am I doing it wrong? Any advice?
UPDATE: I should add, this library is added as a dependency for another library that my app depends on. That is why it is being introduced in the first place. I do not need it included in the EAR, as it is available as a JBoss EAP module.
Wrap your dependency type in a project object model pom as a type:
<dependency>
<groupId>${project.that.has.postgres.as.dependency.groupId}</groupId>
<artifactId>${project.that.has.postgres.as.dependency.artifactId}</artifactId>
<version>${project.that.has.postgres.as.dependency.version}</version>
<type>pom</type>
</dependency>
Related
I have a Jersey Tomcat project B that depends on another similar project A, I am developing on Eclipse.
When I run A on it's own, it runs with no problems. The export configuration for its build path is:
And the deployment assembly for A is:
Then, for project B, I imported project A into the java build path like this:
The build path for project B looks like this:
And the web deployment assembly for project B is:
Project A is listed as a .war, I am not sure if this is related to the issue. The pom.xml for project A lists war as packaging:
<packaging>war</packaging>
The pom.xml for project B mentions project A like so:
<dependency>
<groupId>some.project.A</groupId>
<artifactId>flocktracker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
Eclipse doesn't show any issues until when I try to deploy in a Tomcat server, whe I get this error:
java.lang.NoClassDefFoundError: some/project/A/SomeClassInA
at some.project.B.SomeClassInB.<init>(SomeClassInB.java:##)
If it helps, SomeClassInA is an implementation of org.glassfish.jersey.server.ResourceConfig.
SomeClassInA is mentioned in the web.xml file like so:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>some.projectA.SomeClassInA</param-value>
</init-param>
SomeClassInA is an implementation of javax.ws.rs.ext.ContextResolver<T>
I used right click on project > export > WAR file to examine the contents of the file and I couldn't find the classes of Project A on WEB-INF/classess or elsewhere in the .war file.
Is there something I am missing or that I am doing wrong?
Thanks!
Keeping the Eclipse tooling aside, from a Maven configuration perspective:
Maven does not load classes from a WAR artifact, as it would load from a JAR artifact.
Ideally WAR artifacts are not supposed to be used as a dependency, unless you're building a final EAR artifact.
You have the following choices. All of them require a modification to ProjectB as well:
Although this is the least likely case, if ProjectA is not used for deploying a web application, you could just change its packaging to jar
You could move all the required classes to a separate module that builds a JAR, and use this dependency in both ProjectA and ProjectB.
If you do not want to move the classes to another module/project, you can configure the war plugin in ProjectA to generate a jar artifact alongside the war artifact, using <attachClasses>true</attachClasses>
<project>
...
<artifactId>yourWebapp</artifactId>
<version>yourVersion</version>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
This produces a classes artifact in ProjectA, which can be used in ProjectB as a dependency with <classifier>classes</classifier>
<dependency>
<groupId>yourGroupId</groupId>
<artifactId>yourWebapp</artifactId>
<version>yourVersion</version>
<classifier>classes</classifier>
</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.
I want to package a message-driven bean using Maven. The bean has various dependencies (external libraries) that should be packaged with it. In the end, the resulting package should be deployed on an application server (such as Wildfly).
I tried to create multi-module Maven project where I have a module with "ear" packaging that depends on the actual message-driven bean module which uses "jar" packaging (I also tried "ejb" here). However, when the message-driven bean is called it is not able to acccess its dependencies (no NoClassDefFoundError).
The following change to my "ear" pom fixed this issue because the dependencies are now accessible to the message-driven bean.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<defaultLibBundleDir>lib</defaultLibBundleDir>
</configuration>
</plugin>
</plugins>
</build>
While it basically works now, I feel like I am doing something wrong. Do I really need to change my pom like this? If I have to place the dependencies in the lib directory, why is Maven not doing this by default when building an EAR file.
the EAR/lib folder is the default folder for libraries and every *.jar file inside this folder is automatically loaded by the ear classloader (Java EE 7 Specification)
i think that the EAR/lib folder is come in later specifications of java ee and the maven ear plugin is not updated to this "java ee defaults".
with "defaultLibBundleDir" in maven-ear-plugin all the transitive dependencies are put inside this declared folder. the second is that inside the application.xml folder maven is configuring the "library-directory" element. and this is not required because the "lib" folder is default loaded with the ear classloader.
and this can solved by the setting the maven ear configuration libraryDirectoryMode to NONE
i think it is also best practice to use the fileNameMapping to no-version configuration. this removes the maven versions out of the file names. the maven version is also inside the jar/META-INF/MANIFEST.MF
this is for the jndi name of the modules because the module name came from the jar/war name without the file ending.
your configuration whould look like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<libraryDirectoryMode>NONE</libraryDirectoryMode>
<fileNameMapping>no-version</fileNameMapping>
</configuration>
</plugin>
</plugins>
</build>
Summary
When I try to run a JSF 2.0 application from within Eclipse (on Tomcat 7.0) I get the following exception:
Problem: SEVERE: Error configuring application listener of class org.apache.myfaces.webapp.StartupServletContextListener
java.lang.ClassNotFoundException: org.apache.myfaces.webapp.StartupServletContextListener
Details
I'm learning to develop JSF applications, using Eclipse.
I started with a preconfigured Eclipse project: File->New->Dynamic Web Project->JavaServer Face v2.0 Project.
Using this method Eclipse provides all dependencies. But I want to really learn how everything works. I want to remove the "magic", so I converted my project to a Maven project: Configure->Convert to Maven project.
I then created my pom.xml (based on http://myfaces.apache.org/build-tools/archetypes/myfaces-archetype-helloworld20/index.html), it contains the following:
<build>
<finalName>jsf-facelets-tutorial</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>WebContent/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-api</artifactId>
<version>2.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version>2.0.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
But because I'm unfamiliar with JSF, and because this is an Eclipse "Dynamic Web Project", the project structure is new to me and I'm having trouble understanding which dependencies are coming from Maven and which are provided by the Eclipse "magic".
In Eclipse, my project structure is as follows:
ProjectName
JAX-WS Web Services <-- CAN I REMOVE THIS???
Deployment Descriptor
Java Resources
src/main
Libraries
Apache Tomcat v7.0
el-api.jar
jsp-api.jar
[more...]
JSF 2.0 (Apache MyFaces JSF Core-2.0 API 2.0.2) <-- I REMOVED THIS!!!
EAR Libraries
JRE System Library
Maven Dependencies
el-api-1.0.jar
myfaces-api-2.0.5.jar
myfaces-impl-2.0.5.jar
[more...]
Web App Libraries
Problem
My (very basic) application (login page & welcome page) no longer runs.
When I do the following:
(1) Right click on WebContent/login.xhtml
(2) Run as -> Run on Server
(3) Apache Tomcat v7.0 - JDK6 at localhost
I get the exception:
Problem: SEVERE: Error configuring application listener of class org.apache.myfaces.webapp.StartupServletContextListener
java.lang.ClassNotFoundException: org.apache.myfaces.webapp.StartupServletContextListener
I have the feeling that this is very easy to fix, but I'm too unfamiliar with these frameworks to work it out.
If there are any additional details I should provide (web.xml, faces-config-xml, login.xhtml), let me know and I'll add them.
Thanks!
EDIT
WEB-INF/lib is always empty. From my understanding, it's necessary to copy all dependencies into this folder, that will be required at runtime, and that are not provided by the Web Container. The reasons mine is empty are: (1) I don't know what I need in there (2) I don't know how to automate the process of putting .jar files in there
Under your eclipse Project Properties, select Deployment Assembly from the navigation menu which defines "packaging structure for this Java EE Web Application project." Make sure you have all the project dependencies added here..
Or look into web server directory under workspace/.metadata/.plugins/org.eclipse.wst.server.core\tmp0 to check if the jars have been copied to catalina base.
Sounds like you don't have all the jars in your target folder ready to deploy to tomcat
Try running a maven package in eclipse, right click on project, run as maven package
I hope I'm explaining this as accurately as possible, and I want to know if I set up the maven dependencies correctly, or if there's a better way to do it.
Most of my development team's projects rely on a home-grown jar that is deployed at server class loader. The reason for this jar to reside at this level is to the ease of updating the jar at one place without repackaging each project that's using it, assuming changes made to it are backward-compatible.
I develop my web apps against Jetty in my local development. So, in order for the web apps to work locally, I set up the dependencies this way:-
<dependencies>
<!-- Configuring external jar dependency -->
<dependency>
<groupId>com.test.app</groupId>
<artifactId>app-jar</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${env.EXTERNAL_JAR}</systemPath>
</dependency>
...
</dependencies>
<build>
<plugins>
<!-- Configuring Jetty -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version>
<configuration>
<contextPath>/${project.parent.artifactId}</contextPath>
<jettyEnvXml>${env.JETTY_ENV_XML}</jettyEnvXml>
<scanIntervalSeconds>1</scanIntervalSeconds>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>7777</port>
</connector>
</connectors>
<webAppConfig>
<extraClasspath>${env.EXTERNAL_JAR}</extraClasspath>
</webAppConfig>
</configuration>
</plugin>
...
</plugins>
</build>
In this approach, I set up an environment variable that points to the external jar path, and reference it in my pom.xml as ${env.EXTERNAL_JAR}.
After doing some reading, it seems like using "system" scope is considered a bad practice. So, I installed this external jar in Nexus and change the scope to "provided":-
<dependency>
<groupId>com.test.app</groupId>
<artifactId>app-jar</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
This allows me to compile my project properly, but I'm not sure if it is even possible for me to get rid of the "EXTERNAL_JAR" environment variable completely because it's still needed by Jetty for the runtime to work properly. My take is using "provided" scope is a little tedious and more work, because I now need to remember to update the jar in Nexus when it is modified AND I still need to update the jar located at the path pointed by the environment variable.
Is there a way for me to expose the external jar to Jetty through maven dependencies, yet not being packaged into the project when the war file is built?
What are you advice on this? Should I just stick with "system" scope so that I just need to update the jar at one place, or should I use "provided" scope? Or if there's even a better way to do this?
Thanks much.
You should be able to add dependencies to the jetty plugin. And then I have the provided scope for the project itself.
http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin
as in
<project>
...
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<systemProperties>
<systemProperty>
<name>logback.configurationFile</name>
<value>./src/etc/logback.xml</value>
</systemProperty>
</systemProperties>
</configuration>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.15</version>
</dependency>
</dependencies>
</plugin>
...
<project>
The best thing to do is setup an external repository with your dependency, and add it to your pom.
<repositories>
<repository>
<id>my-repo</id>
<name>my-repo</name>
<url>http://your.repo.url</url>
</repository>
</repositories>
and then you can add your dependency as
<dependency>
<groupId>com.test.app</groupId>
<artifactId>app-jar</artifactId>
<version>1.0</version>
</dependency>
I approve of provided. Provided means - download the dependency for compile-time, but I expect to see it on classpath on the application server.
I did not realize you care only for your local development, so the following would be useful if you were running Jetty on an external server:
Maven will let you deploy a file to a server using the Wagon plugin. So a part of your build process could be pushing the proper .jar into your Jetty server. That way you would not have to do it manually. I would prefer this solution to running a local Maven repository on the Jetty server as suggested by #Paul.
If you wanted to be super-clever (usually a bad idea), you might try to set up a repository directly on the machine with Jetty, that would serve the jar directly from your Jetty install. That way you would not have to modify Nexus, the jars would be only at one place. You can even set up Nexus to mirror another repository, so it could pick things up automatically.
It is a bad practice to modify .jar contents and keep the same Maven coordinates. So this "clever" approach would not work that great anyway.