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)
Related
I want to download a zip file via mavens POM.XML, but based on the OS i need different URLs (Linux/Windows).
How can I change the URL based on the OS maven is executed? (locally, its Windows, on Jenkins its then Linux)
This is how the plugins part of my POM.XML looks like:
<build>
<plugins>
<plugin>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<executions>
<execution>
<!-- the wget goal actually binds itself to this phase by default -->
<phase>process-resources</phase>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<url>https://test/chromedriver_win32.zip</url>
<unpack>true</unpack>
<outputFileName>chromedriver</outputFileName>
<outputDirectory>${project.build.directory}/chromeDriver</outputDirectory>-->
<outputDirectory>${user.home}/localdata/tools/chromeDriver</outputDirectory>
<overwrite>true</overwrite>
<skipCache>true</skipCache>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I'm starting to catch up on the capabilities of the repackage goal in spring-boot-maven-plugin.It looks promising, but I need to fine-tune it a little.
I can easily do that by creating a layers.xml file somewhere in my project, but the problem is that I don't only have 1 project, but rather half a dozen. All of the projects need the same kind of layering, but I don't really want to copy the same configuration for every project I want to use it on.
A nice-looking solution would be to extract that configuration file into a separate jar for example and have the plugin take the config file from there, but I see no way of doing it. Is there any other solution that doesn't involve me copying the configuration file to every project I have?
Unfortunately, even though the projects I have use the same parent, but are not in the same multi-module project.
I managed to work out a solution.
Before asking the question my spring-boot-mave-plugin config looked something like this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<phase>package</phase>
<configuration>
<layers>
<enabled>true</enabled>
<configuration><!-- something like classpath:layers.xml --></configuration>
</layers>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>artifact</groupId>
<artifactId>with-layers.xml</artifactId>
<version>...</version>
</dependency>
</dependencies>
</plugin>
The solution becomes one step more convoluted, by bringing in the maven-dependency-plugin, which downloads the before mentioned dependency and unpacks it in the build folder with this configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy-shc-build-tools</id>
<goals>
<goal>unpack</goal>
</goals>
<phase>package</phase>
<configuration>
<artifactItems>
<artifactItem>
<groupId>artifact</groupId>
<artifactId>with-layers.xml</artifactId>
<version>...</version>
<type>jar</type>
<outputDirectory>${project.build.directory}</outputDirectory>
<includes>**/layers.xml</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
<configuration>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</plugin>
In turn, the line <configuration><!-- something like classpath:layers.xml --></configuration> becomes <configuration>${project.build.directory}/layers/layers.xml</configuration>.
The documentation for Spring Boot Maven Plugin states you can set the path to the layers.xml manually, so why not have all pom.xml point to the same location?
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.2.RELEASE</version>
<configuration>
<layers>
<enabled>true</enabled>
<configuration>${project.basedir}/../layers.xml</configuration>
</layers>
</configuration>
</plugin>
</plugins>
</build>
</project>
The /../ means one level higher from the project directory. So say you have a bunch of projects in one directory, put the layers.xml there and it'll work.
Another approach could be to reuse the Maven Plugin declaration by moving it to a so-called parent POM. This is a technique where the common/shared parts of the POM files of a series of projects is moved to a single POM file (the parent POM). Here's an example
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
Im trying to get the properties-maven-plugin to read from my .properties file. Flyway (which im trying to use the properties for) just keeps throwing errors about the db url being malformed, but works if i set the values within the pom.xml itself, rather than using the properties read from file.
Im using eclipse with the m2e plugin.
plugin config to read from .properties
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>src/main/resources/config.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
Flyway config where the properties are being used
<plugin>
<groupId>com.googlecode.flyway</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>flyway:migrate</goal>
</goals>
</execution>
</executions>
<configuration>
<driver>${db.driver}</driver>
<url>${db.url}</url>
<user>${db.user}</user>
<password>${db.password}</password>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
</dependencies>
</plugin>
config.properties located in /src/main/resources/
# Database details
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/dbname
db.user=username
db.pass=password
Ive tried looking through several other stackoverflow threads but none of the solutions seem to work. I'm new to maven and the whole thing seems to be throwing me, anyone got a light to shed?
There are basically two ways you can execute the Flyway migrate goal:
As part of a lifecycle phase: You have configured the Flyway plugin to be executed during the compile phase. That means you can just enter mvn compile and Flyway will be executed along with all other goals that are part of that lifecycle phase and all previous phases. Everything works fine, except you have a slight misconfiguration: The goal must not be prefixed. In order to fix this you have to provide the goal without prefix:
<goals>
<goal>migrate</goal>
</goals>
Now the execution works. Flyway gets all parameters from the properties-maven-plugin because it is executed in a previous phase.
Direct invocation: If you execute Flyway with mvn flyway:migrate, the plugin is invoked independent of any lifecycle phases. Since no phase is executed, the properties-maven-plugin is also not executed because it relies on the initialize phase - which effectively doesn't set any parameters. That's why Flyway complains about missing parameters.
Solution:
If you want the properties-maven-plugin to work together with Flyway you have to execute Flyway as part of a lifecycle. If you don't want to invoke it with every compile phase, you could create a separate profile and only run this profile whenever you need a Flyway migration with mvn compile -PflywayMigration:
<profiles>
<profile>
<id>flywayMigration</id>
<build>
<plugins>
<plugin>
<groupId>com.googlecode.flyway</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>migrate</goal>
</goals>
</execution>
</executions>
<configuration>
<driver>${db.driver}</driver>
<url>${db.url}</url>
<user>${db.user}</user>
<password>${db.password}</password>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</profile>
</profiles>
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.