I'm developping an OSGI email client with Maven following component-based software engineering. I must make sure that the dependencies between all my components are resolved inside of the OSGI container, so I cannot copy the dependencies inside the generated JARs, otherwise there would be no point using OSGI. But there is one dependency I really have to copy inside of the JAR, it's javax.mail, because I cannot find any OSGI-compatible bundle that does emailing.
To do that, I have seen this page: https://maven.apache.org/plugins/maven-dependency-plugin/examples/copying-artifacts.html
So I edited my pom.xml:
<project>
...
<build>
<plugins>
<plugin> <!-- to edit the MANIFEST.MF, required for OSGI -->
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>4.2.1</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Class-Path>lib/</Class-Path>
... OSGI instructions ...
</instructions>
</configuration>
</plugin>
<plugin> <!-- to copy the dependencies -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
But the <artifactItems> tag doesn't seem to work. When I mvn install, it copies ALL the dependencies into a dependency/ folder and not a lib/ folder. How can I do to copy only the javax.mail JAR into a folder named lib/?
Thank you for your help.
The maven-bundle-plugin allows to embed dependencies:
https://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html
<Embed-Dependency>javax.mail|javax.mail-api</Embed-Dependency>
You mixed up the goals copy-dependencies and copy. Replace copy-dependencies by copy.
http://maven.apache.org/plugins/maven-dependency-plugin/copy-mojo.html
My problem is that i want to extract files from a .jar file with maven but only if the files do not exist in the output directory. So if i have a file /src/META-INF/beans.xml then i only want the persistence.xml extracted, etc.
Sadly the maven-plugin irgnores all combinations with <overWrite>false</overWrite> that i tried.
Question: Any idea what i am doing wrong? Is it possible?
<build>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>unpack</id>
<phase>validate</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId> ... </groupId>
<artifactId> ... </artifactId>
<version>${project.version}</version>
<outputDirectory>${basedir}/src/META-INF</outputDirectory>
<includes>beans.xml,persistence.xml</includes>
<overWrite>false</overWrite>
</artifactItem>
</artifactItems>
<overWriteIfNewer>false</overWriteIfNewer>
<overWrite>false</overWrite>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteReleases>false</overWriteReleases>
</configuration>
</execution>
</executions>
</plugin>
...
</build>
The simple overWrite property actually doesn't exist as a property of the plugin, hence it is simply ignored by the plugin.
Moreover, you are writing to ${basedir}/src/META-INF, your project, which is probably not the best option, but in some cases could still be reasonable.
You hence want to write it only once, during the validate phase of the project and most probably only during the first build: that is, if exists, don't override it again.
for these requirements the following may suit better:
Use a Maven profile
Use the activation option for files missing: that is, if the file is not there (first time ever) activate the profile which will execute your plugin configuration; when the file is already there, don't activate the profile, no action obviously won't override anything
<profiles>
<profile>
<id>unpack-files</id>
<activation>
<file>
<missing>${basedir}/src/META-INF/beans.xml</missing>
</file>
</activation>
<build>
<plugins>
<!-- move here the maven-dependency-plugin unpack execution -->
</plugins>
</build>
</profile>
</profiles>
As such you would still have full control of this logic:
It will be activated when the file is not there, first execution
It can still be activated on demand, via its id (mvn clean install -Punpack-files)
I have a situation where i need to Unpack a spring jar and replace a file in that package with my .class file and repackage it back as jar. I understood that this can be done in Maven. So i created a maven project and i added the .java(to be replace in the Spring jar) to it . Here is my Project structure.
here is my pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<name>repackage</name>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.4.6</version>
<packaging>pom</packaging>
<build>
<plugins>
<!-- Unpacking -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6.SEC03</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>target</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- Packing -->
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classesDirectory>target</classesDirectory>
<classifier>sample</classifier>
</configuration>
</execution>
</executions>
</plugin>-->
</plugins>
</build>
</project>
I am able to unpack the spring jar using maven dependency plugin and i figured out how to pack it back to a jar using maven-jar-plugin. The part i am struggling to understand 1) how convert my .java file into a .class file. As the packaging is pom type <packaging>pom</packaging> I am not able to compile the java file(JdkVersion.java). if successful in creating the class file 2) How to replace this .class file into unpacked spring jar as the file i need to replace is inside the sub directory of /springpackage
You don't have to. Spring is an open source project just clone its source code https://github.com/spring-projects/spring-framework?files=1 and update the code and create a package using simple mvn package command
i have a problem and I'm not able to solve or understand the hole workflow behind this process.
I use eclipse with maven.
This is my simple test pom.xml
...
<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<xdebug>true</xdebug>
<verbose>true</verbose>
<keep>true</keep>
<packageName>abc.model</packageName>
<sourceDestDir>${project.build.directory}/generated-sources/wsimport/</sourceDestDir>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/wsimport/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
The jaxws-maven-plugin generate the files in the sourceDestDir. The build-helper-maven-plugin add the files during the maven install process the to the correct folder and also into the resulting jar file. So far so good.
But I'm not able to use the generated files/classes in eclipse. So in eclipse maven does not recognize the files as source or does not but this in the source path. Did I make an mistake or did I miss something?
Thanks for your help.
Update:
I observer a strange behavior. Same test project same pom file. If I import this existing Maven Project in eclipse it works like expected. I can directly use the generated files as source.
But if I delete this source folder, I'm still not able to restore this with maven.
I want to add a jar file through the systemPath from the local file-system relative to my project directory structure, not on a remote repository. I added the dependency declaration but maven doesn't do anything else with it.
In the declaration below, I want the jar file copied to my target web-inf/lib directory and also jarred as part of the war file. At present, that doesn't happen. How would I get the jar file copied to my war file?
This is the output from debug maven mode:
DEBUG] cglib:cglib-nodep:jar:2.2:test (setting scope to: compile)^M
DEBUG] Retrieving parent-POM: org.objenesis:objenesis-parent:pom:1.2 for project: null:objenesis:ja
DEBUG] org.objenesis:objenesis:jar:1.2:test (selected for test)^M
DEBUG] org.javap.web:testRunWrapper:jar:1.0.0:system (selected for system)^M
DEBUG] Plugin dependencies for:
...
<dependency>
<groupId>org.javap.web</groupId>
<artifactId>testRunWrapper</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/testRunWrapper.jar</systemPath>
</dependency>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>WebContent</directory>
</resource>
</webResources>
</configuration>
</plugin>
OK, I did this: Note the directory structure at the bottom.
With the approach below, the jar file from the relative project path is treated as a first class citizen like the other jars. The listing below corrects my original problem. With the pom.xml listing below, the jar file is copied to my target directory.
<repositories>
<repository>
<id>JBoss</id>
<name>JBoss Repository</name>
<layout>default</layout>
<url>http://repository.jboss.org/maven2</url>
</repository>
<repository>
<id>my-local-repo</id>
<url>file://${basedir}/lib/repo</url>
</repository>
</repositories>
<dependency>
<groupId>testRunWrapper</groupId>
<artifactId>testRunWrapper</artifactId>
<version>1.0.0</version>
</dependency>
$ find repo
repo
repo/testRunWrapper
repo/testRunWrapper/testRunWrapper
repo/testRunWrapper/testRunWrapper/1.0.0
repo/testRunWrapper/testRunWrapper/1.0.0/testRunWrapper-1.0.0.jar
Using the maven dependency plugin does the job:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
<includeScope>system</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Don't use system. To do what you want, just declare as a regular (compile) dependency and use mvn install:install-file into your local repository. Everything else will work as you want (lib will be copied, etc.) That will mean that the build will only work on your machine, however.
To properly fix this for your (internal) team, you will want to set up a repository (e.g. Artifactory, Nexus, or Archiva). This is almost a must for team use of Maven.
If this is for public (e.g. open source) use you can either mimic a repository via an http server or put up a real repository.
try something like this (using Ant plugin to manually put the jar to output directory):
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy file="${project.basedir}/pathToJAR.jar"
todir="${project.build.directory}/outputFileName/WEB-INF/lib"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
AFAIK, system scoped dependencies are somewhat like those with provided scope and thus are not included in the target artifact. Why don't you install the dependency into your local repository instead?
From the doc:
system
This scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.
In case this answer didn't work for you as it didn't for me and you know that system is a bad scope, you can try this solution where you are Installing the jar by using install-plugin (scroll down a bit), which installs the JAR into your actual local Maven-repository. Basically you only need to add this plugin to your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>myGroupId</groupId>
<artifactId>myArtifactId</artifactId>
<version>myVersion</version>
<packaging>jar</packaging>
<file>${basedir}/lib/xxx.jar</file>
</configuration>
</execution>
</executions>
</plugin>
Fill in the appropriate values for groupId, artifactId and version and put your original jar file into the <project-home>/lib-directory and fix file above. You can add more execution-sections, but then don't forget to add ids there, like:
<execution>
<id>common-lib</id>
Everybody who updates from the code-repo needs to call mvn initialize once.
And all Eclipse-enthusiasts may add this to pom.xml, too, to get rid of errors in Eclipse:
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<versionRange>[2.4,)</versionRange>
<goals>
<goal>install-file</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute></execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
The problem with using a reference to the file system is that dependent projects will not be able to globally access this jar file. i.e. the dependent project's ${basedir} is different and thus the .jar file won't be found.
Global repositories on the other hand are universally accessible.