Maven War Plugin: Copy webResources after resources - maven

I am using the maven-war-plugin to copy the webapp resources and a few external resources to the target directory and then build the war file.
Here is the plugin configuration,
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- Importing React App which is not in the build path -->
<webResources>
<resource>
<directory>react/build</directory>
<targetPath>ui/build</targetPath>
</resource>
</webResources>
</configuration>
<executions>
<execution>
<id>default-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
</plugin>
This configuration works well, but the external resources (webResources) are copied first and then the build path content is copied.
Build steps,
Copy external resources (webResources)
Copy resources from build path (warSourceDirectory)
Build War file.
This is an extract from the maven build logs,
[INFO] --- maven-war-plugin:2.2:war (default-war) # ReactProject ---
...
[INFO] Copying webapp webResources [...\react\build] to [...\target\ReactProject-0.0.1]
[DEBUG] + \ui\build\app.js has been copied.
...
[INFO] Copying webapp resources [...\ReactProject\src\main\webapp]
[DEBUG] + \ui\html\index.html has been copied.
...
[INFO] Building war: ...\ReactProject\target\ReactProject-0.0.1.war
Due to this behavior if similar content is present in the build path it overwrites the content copied from the react folder. Also, it would be more intuitive if the external content is copied after the build path resources are configured.
Is there a way to configure the webResources to be copied after the main resources?
Complete pom file
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>ReactProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>ReactProject</name>
<description>React Project</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
...
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- Importing React App which is not in the build path -->
<webResources>
<resource>
<directory>react/build</directory>
<targetPath>ui/build</targetPath>
</resource>
</webResources>
</configuration>
<executions>
<execution>
<id>default-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Related

Include Maven Site HTML pages in JAR's resources

I've got a Maven project that builds a JAR file.
It also creates a site (using maven-site-plugin) that describes information about the project.
I'd like to include the resultant html pages generated by the maven-site-plugin in the resources of the created JAR so that they can be accessed at runtime by a help system.
Is this possible? If so, how?
I've tried using the site:jar goal but this always creates an additional JAR with "-site" appended, as per the documentation.
I've solved this by using maven-resources-plugin to copy the site from the ${project.build.directory}/site directory to ${project.build.directory}/classes, which is the contents of the final JAR.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.me</groupId>
<artifactId>site-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<site.directory>${project.build.directory}/site</site.directory>
</properties>
<build>
<resources>
<resource>
<directory>${site.directory}</directory>
</resource>
</resources>
<plugins>
<plugin>
<!-- Include the maven site in the final JAR - we do this by running site:site BEFORE install -->
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<resources>
<resource>
<directory>${site.directory}</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

yuicompressor maven is not working

I am working in Spring boot web application with maven build. I want to compress all js & css files. I have chosen YUI compression. When I build my application yui compression not happened. I am getting following message for all js & css files.
[INFO] nothing to do, **css\base.css is younger than original, use 'force' option or clean your target
What I am missing ?
Here is my pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>MyApp</groupId>
<artifactId>MyApp</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<!-- <url>http://maven.apache.org</url> -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>
<dependencies>
my dependencies
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<nosuffix>true</nosuffix>
</configuration>
</plugin>
</plugins>
</build>
</project>
Project structure :
It's not an error and works as expected. The plugin creates a minified version of the resource only when it's minified version doesn't exist or when source file has been changed. When plugin found that minified version was created later than source file, it doesn't do minification and assumes that nothing to be done.
As you can see, message suggests you to use force option (in this case, minified version will be always generated but it will be slower) or clean the target (execute mvn clean to remove all generated files so they will be generated again).
UPDATED:
I was able to reproduce the issue. It happens because yuicompressor-maven-plugin is being executed after maven-resource-plugin. The former was copied all the files from src/main/resources to the target directory and when yuicompressor was being executed, it found that the files already here (non-minified of course) and show this message.
To fix this, first, we need to configure resource plugin to exclude resources:
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources/public</directory>
<excludes>
<exclude>*.js</exclude>
<exclude>*/*.js</exclude>
</excludes>
</resource>
</resources>
</build>
But it didn't solve it because after that I found that yuicompressor doesn't process these files. This is because the plugin was looking in the wrong directory and we have to configure it also:
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.5.1</version>
...
<configuration>
<nosuffix>true</nosuffix>
<sourceDirectory>src/main/resources/public</sourceDirectory>
</configuration>
</plugin>
Use -Dmaven.clean.failOnError=false to mvn command.
example: mvn clean -Dmaven.clean.failOnError=false
Just by adding Force option I resolved this issue:
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<nosuffix>true</nosuffix>
<force>true</force>
<sourceDirectory>src/main/resources/static</sourceDirectory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<excludes>
<exclude>**/*.min.js</exclude>
<exclude>**/*.min.css</exclude>
</excludes>
</configuration>
</plugin>

How to share a filtered resource at generate-sources phase in a multi module project?

I have a parent project with 3 child projects:
parent
project-1
/src/main/resources/config.xml
project-2
/src/main/resources/config.xml
project-3
/src/main/resources/config.xml
The configuration config.xml is used during the generate-sources phase. For the three projects, the config.xml is exactly the same. However, the usage of this config.xml is different for each project.
In project-X, I am referring to config.xml as following:
<build>
<plugins>
<plugin>
<groupId>some-group</groupId>
<artifactId>some-artifact</artifactId>
<executions>
<execution>
<goals>
<goal>some-goal</goal>
</goals>
<configuration>
<input>src/main/resources/config.xml</input>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
What is the best way to share this common config.xml between all 3 projects?
You can use the build-helper-maven-plugin here.
PROJECT STRUCTURE
shared-resources-project
+-src
+-main
+-resources
`config.xml
+-project-A
`pom.xml
+-project-B
`pom.xml
+-project-C
`pom.xml
`pom.xml
shared-resources-project/pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my</groupId>
<artifactId>shared-resources-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>project-A</module>
<module>project-B</module>
<module>project-C</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>add-resource</id>
<phase>generate-sources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<filtering>true</filtering>
<directory>${project.parent.basedir}/src/main/resources</directory>
<includes>
<include>config.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>some-group</groupId>
<artifactId>some-artifact</artifactId>
<executions>
<execution>
<id>some-plugin-job</id>
<phase>generate-sources</phase>
<goals>
<goal>some-goal</goal>
</goals>
<configuration>
<input>${project.build.outputDirectory}/config.xml</input>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
shared-resources-project/src/main/resources/config.xml
<config>
<parameter>${custom-value}</parameter>
</config>
project-X/pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>my</groupId>
<artifactId>shared-resources-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>project-X</artifactId>
<properties>
<custom-value>Project-X Value</custom-value>
</properties>
</project>
Now, let's build the project:
D:\workspaces> cd shared-resources-project
D:\workspaces\java\shared-resources-project> mvn clean install
Some notes:
The build-helper-maven-plugin will add the common config.xml file as a resource to Project-X.
Then the Maven resources plugin (MRP) will copy config.xml to the project output directory (target directory by default). During the copy, MRP will also replace ${custom-value} with the specific value provided by Project-X.
The final config.xml will be available to another plugin as long as the other plugin is bound to the generate-source phase AND its declaration appears AFTER the build-helper-maven-plugin declaration. Maven (3.0.4+ at least) calls the plugins in their order of apparition in the pom.xml.

Maven ear plugin multiple artifacts content

Lets assume that I have a web project and several environments where it could be deployed. And I want Maven to build several artifacts at once (e.g. for dev an prod). I have an A-war module and an A-ear module (which contains A-war). Each war artifact could contain information which is related only to its environment.
First I configured a pom.xml file for A-war module:
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<id>package-prod</id>
<phase>package</phase>
<configuration>
<classifier>prod</classifier>
<webappDirectory>${project.build.directory}/${project.build.finalName}-prod</webappDirectory>
<webResources>
<resource>
<directory>src/env/prod</directory>
</resource>
</webResources>
</configuration>
<goals>
<goal>war</goal>
</goals>
</execution>
<execution>
<id>package-dev</id>
<phase>package</phase>
<configuration>
<classifier>dev</classifier>
<webappDirectory>${project.build.directory}/${project.build.finalName}-dev</webappDirectory>
<webResources>
<resource>
<directory>src/env/dev</directory>
</resource>
</webResources>
</configuration>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<finalName>A-war</finalName>
</build>
This works fine - 2 *war*s are created in target folder: A-war-prod and A-war-dev.
Now I want to build ear artifact for each of these war.
Here is the main content of pom.xml in A-ear module:
<dependencies>
<dependency>
<groupId>gr.id</groupId>
<artifactId>A-war</artifactId>
<version>0.0.1-SNAPSHOT</version>
<classifier>prod</classifier>
<scope>provided</scope>
<type>war</type>
</dependency>
<dependency>
<groupId>gr.id</groupId>
<artifactId>A-war</artifactId>
<classifier>dev</classifier>
<version>0.0.1-SNAPSHOT</version>
<scope>provided</scope>
<type>war</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>package-dev</id>
<phase>package</phase>
<configuration>
<classifier>dev</classifier>
<version>5</version>
<modules>
<webModule>
<groupId>gr.id</groupId>
<artifactId>A-war</artifactId>
<classifier>dev</classifier>
<contextRoot>/A-war</contextRoot>
<bundleFileName>/A-war.war</bundleFileName>
</webModule>
</modules>
</configuration>
<goals>
<goal>ear</goal>
</goals>
</execution>
<execution>
<id>package-prod</id>
<phase>package</phase>
<configuration>
<classifier>prod</classifier>
<version>5</version>
<modules>
<webModule>
<groupId>gr.id</groupId>
<artifactId>A-war</artifactId>
<classifier>prod</classifier>
<contextRoot>/A-war</contextRoot>
<bundleFileName>/A-war.war</bundleFileName>
</webModule>
</modules>
</configuration>
<goals>
<goal>ear</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<finalName>A-ear</finalName>
</build>
It also builds 2 ear**s: A-ear-dev.ear and A-ear-prod.ear. And each of these *ear*s contains an A-war.war artifact. And everything would be fine except of one small detail: these **war files are the same. I mean A-ear-dev.ear contains A-war-dev.war (which is renamed to A-war.war) but A-ear-prod.ear contains the same A-war-dev.war instead of its own A-war-prod.war.
Moreover when I'd changed the order of executions (moved creating of prod higher than dev) then these *ear*s both contained A-war-prod.war.
As I can see from maven output, when starting building ear**s it copies the first war into the folder for the first **ear but for the second it does not:
[INFO] --- maven-ear-plugin:2.8:ear (package-dev) # A-ear
---
[INFO] Copying artifact [war:gr.id:A-war:dev:0.0.1-SNAPSHOT] to [/A-war.war]
[INFO] Including custom manifest ....
[INFO] Copy ear sources to ...
[INFO] Building jar: <location>\A-ear\target\A-ear-dev.ear
....
[INFO] --- maven-ear-plugin:2.8:ear (package-prod) # A-ear ---
[INFO] Copy ear sources to ...
[INFO] Including custom manifest file ...
[INFO] Building jar: <location>\A-ear\target\A-ear-prod.ear
So maybe anyone has an idea on how to force maven copy war file each time?
As I found out, when Maven is copying war file into the temp directory, it doesn't rewrite it - if there is a file with the same name, then it will not be replaced. So after the first artifact copying, it copied always the first artifact which is pointed in execution module.
All other artifacts were not copied. So this artifact was placed in all result ears.
So the solution for this issue is to specify working directory for each execution tag, like:
<execution>
<id>package-prod</id>
<phase>package</phase>
<configuration>
<workDirectory>target/prod</workDirectory>
<classifier>prod</classifier>
<version>5</version>
<modules>
<webModule>
<groupId>gr.id</groupId>
<artifactId>A-war</artifactId>
<classifier>prod</classifier>
<contextRoot>/A-war</contextRoot>
<bundleFileName>/A-war.war</bundleFileName>
</webModule>
</modules>
</configuration>
<goals>
<goal>ear</goal>
</goals>
</execution>

maven-resources-plugin error using copy-resources goal: 'resources', 'outputDirectory' missing or invalid

I'm trying to use the maven-resources-plugin to do some filtering using the copy-resources goal, and ran into the following error:
Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:2.5:copy-resources (default-cli) on project bar: The parameters 'resources', 'outputDirectory' for goal org.apache.maven.plugins:maven-resources-plugin:2.5:copy-resources are missing or invalid
To isolate the problem, I created a very simple pom.xml, copied pretty nearly verbatim from http://maven.apache.org/plugins/maven-resources-plugin/examples/copy-resources.html, ran it, and got the same error.
I'm invoking it with
mvn resources:copy-resources
Any ideas? Here's the test pom.xml.
<?xml version="1.0" encoding="UTF-8"?>
<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>foo</groupId>
<artifactId>bar</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/extra-resources</outputDirectory>
<resources>
<resource>
<directory>src/non-packaged-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The main problem you had is that you are invoking the plugin goal directly using
mvn resources:copy-resources
which does not necessarily create the output directory. Instead call the correct Maven lifecycle phase.
mvn process-resources
For a complete list of the lifecycle phases just run the mvn command without anything..
In general it almost always better to invoke a lifecycle phase rather than a goal directly since it guarantees that any preconditions are met (e.g. cant compile test classes before the classes to be tested..).
Check if #bmargulies answer works for you. You can refer to these examples.
In any case, you do not need to use <pluginManagement> to achieve this. <pluginManagement> is used in multi-module scenarios to facilitate inheritance of plugin configurations.
You need to move the configuration out of execution element. The following snippet works.
<?xml version="1.0" encoding="UTF-8"?>
<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>foo</groupId>
<artifactId>bar</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<outputDirectory>${basedir}/target/extra-resources</outputDirectory>
<resources>
<resource>
<directory>src/non-packaged-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Just remove the executions and their configuration. Normally you might want to define resources in <build> > <resources> respectively <build> > <testResources> (see http://maven.apache.org/plugins/maven-resources-plugin/examples/resource-directory.html) directly not within the plugin config using the default lifecycle process-(test-)resources which is automatically hooked by copy-(test-)resources..
Yes, it's a bad example on their page!

Resources