Loading resources in a maven project with exec-maven-plugin - java

Having two issues here. I have a Maven project, with pom.xml specifying resources as
<resources>
<resource>
<directory>src/main/sql</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
And then I have an exec-maven-plugin section such as
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>RunMyTest</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.foo.RunMyTest</mainClass>
<classpathScope>test</classpathScope>
<addResourcesToClassPath>true</addResourcesToClassPath>
</configuration>
</execution>
</executions>
</plugin>
(Here, com/foo/RunMyTest.java lives in src/test/java).
Now, I have two issues. First, somewhat minor: if I run this with
mvn -X exec:java#RunMyTest
I see in the output [DEBUG] (f) addResourcesToClasspath = false. Does <addResourcesToClassPath>true</addResourcesToClassPath> not have any effect?
But that can be for now overridden with running
mvn exec:java#RunMyTest -DaddResourcesToClasspath=true
Now I see [DEBUG] (f) addResourcesToClasspath = true. BUT! The problem is, in my code I call code from a dependency, which in turn uses ClassLoader.getSystemClassLoader().getResource("foo.txt"); where foo.txt is under src/main/sql -- and this returns null. Testing in my code by doing RunMyTest.class.getClassLoader().getResource("foo.txt"), however, works. It appears that the system classloader does not see the resources path. Is there any nice way around it?

Related

Maven release not calling resources:resources plugin

I'm trying to deploy a maven project and upgrade the versions by executing the maven release plugin on TeamCity. I am able to successfully do this - however, the resources:resources plugin is no longer executed. Or more accurately, it is executed but not doing the expected changes. When I run a maven package or install however, it works. Not sure what it is I'm missing. Any help would be appreciated.
Below is my code
Parent pom
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<tagNameFormat>v#{project.version}</tagNameFormat>
<autoVersionSubmodules>true</autoVersionSubmodules>
<releaseProfiles>releases</releaseProfiles>
<localCheckout>true</localCheckout>
<arguments>-Dmaven.javadoc.skip=true -Dmaven.test.skipTests=true -Dmaven.test.skip=true -DCONTINUOUS_BUILD_ID=%build.counter% -DGIT_COMMIT=%build.vcs.number% -DGIT_BRANCH=%vcsroot.branch%</arguments>
</configuration>
<executions>
<execution>
<id>prepare</id>
<goals>
<goal>prepare</goal>
</goals>
<configuration>
<pushChanges>false</pushChanges>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
Child pom
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<!-- Adds ${buildNumber} to buildNumber.properties -->
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>application_local.properties</exclude>
</excludes>
</resource>
</resources>
</build>
I run the following command:
mvn -B -e initialize release:branch release:clean release:prepare release:stage -DCONTINUOUS_BUILD_ID=%build.counter% -DGIT_COMMIT=%build.vcs.number% -DGIT_BRANCH=%vcsroot.branch%...
And I have in my child project in the src/main/resources folder a file called application-deployed.properties with the following lines which is what I want to change.
# build information by team city
child.propject.buildNumber=#CONTINUOUS_BUILD_ID#
child.propject.buildVersion=#GIT_COMMIT#
child.propject.buildBranch=#GIT_BRANCH#
Any help is much appreciated
maven-resources-plugin doesn't have access to the parameters you pass in the command line. Reason for this is that deploy goal (which includes resources:resources, among others) is invoked by maven-release-plugin in a separate Maven execution.
In order to overcome this limitation, goals of maven-release-plugin accept arguments parameter that could be used to pass parameters to aforementioned separate Maven executions. Try to modify your command line the following way:
mvn -B -e initialize release:branch release:clean release:prepare release:stage -Darguments="-DCONTINUOUS_BUILD_ID=%build.counter% -DGIT_COMMIT=%build.vcs.number% -DGIT_BRANCH=%vcsroot.branch%"
I was able to solve the issue by adding the following to the maven release plugin in the parent pom
<arguments>-Dmaven.javadoc.skip=true -Dmaven.test.skipTests=true -Dmaven.test.skip=true -DCONTINUOUS_BUILD_ID=${CONTINUOUS_BUILD_ID} -DGIT_COMMIT=${GIT_COMMIT} -DGIT_BRANCH=${GIT_BRANCH}</arguments>
and then calling my initial command
mvn -B -e initialize release:branch release:clean release:prepare release:stage -DCONTINUOUS_BUILD_ID=%build.counter% -DGIT_COMMIT=%build.vcs.number% -DGIT_BRANCH=%vcsroot.branch%...

Maven and Java Extension

I am trying to build and test a JavaFX application on a headless build server. Locally I am using TestFX and Monocle https://github.com/TestFX/Monocle and its working fine. However, I had to manually install Monocle into the java Extensions folder as per this question: JavaFX + maven + TestFX + monocle don't work together
Now I need to use a headless build server to automate our deployment. I can't figure out how to get this Java extension installed correctly with Maven, without doing it manually. This seemed to be the right feature: https://maven.apache.org/pom.html#Extensions,
<extensions>
<extension>
<groupId>org.testfx</groupId>
<artifactId>openjfx-monocle</artifactId>
<version>8u76-b04</version>
</extension>
</extensions>
but the tests fail with a NoClassDefFoundException (which doesn't happen if I manually build the jar into the Extensions). I don't know how to debug this, or if I'm even using the right feature. Any suggestions?
I had a similar headache some time ago. I solved it by copying both openjfx-monocle and all extensions from the extensions folder in a folder under /target and then set the extensions system property to that path. This way I could avoid the NoClassDefFoundException and also successfully run all test on Jenkins. Here is the profile part:
<!--
This profile is used to make headless tests work with the Monocle Platform.
It first copies the extensions from the JDK to the target/java-extensions folder.
Then copies the openjfx-monocle implementation to the same folder.
Afterwards it sets the extensions path to the folder with the copied extensions and the monocle platform.
-->
<profile>
<id>headless-tests</id>
<activation>
<property>
<name>headless.tests</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-external-jars</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/java-extensions</outputDirectory>
<resources>
<resource>
<directory>${java.home}/lib/ext/</directory>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-monocle-to-extensions</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/java-extensions</outputDirectory>
<resources>
<resource>
<directory>src/test/resources/test-lib</directory>
<includes>
<include>openjfx-monocle-8u76-b04.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<argLine>-Djava.ext.dirs=${project.basedir}/target/java-extensions</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
In my case I copied the monocle jar from maven in the src/test/resources folder. This can further be improved by using Maven Dependency Plugin to copy the monocle jar directly with maven instead having it in src/test/resources.

How to include filtered resources into WEB-INF/classes using maven-resources-plugin?

I'm using the maven-resources-plugin because I need to use a custom delimiter when doing my filtering. My artifact is a WAR.
I have some resources in my src/main/resources directory. Normally, when packaging a WAR, anything in this directory ends up in WEB-INF/classes. But I need those resources to be filtered first, then placed into the WEB-INF/classes directory. I'm having a hard time configuring the maven-resources-plugin to do that. Is there a way?
My POM looks like this:
<build>
<finalName>my-app</finalName>
<filters>
<filter>${basedir}/src/main/properties/base.properties</filter>
</filters>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<useDefaultDelimiter>false</useDefaultDelimiter>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<outputDirectory>${project.build.directory}</outputDirectory>
<resources>
<resource>
<directory>
${basedir}/src/main/resources
</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Short answer:
The phase is wrong, validate is the second phase, should only be used for validation of the build environment and comes before the default process-resources phase, so your correct files become overriden.
Long answer:
Basically, you have two options two fix your problem:
Use a different / new execution for copying
If you really need different behaviours.
In that case, your phase is wrong. What happens is:
in the phase validate (Why there?), the resources are correctly filtered and copied
in the phase process-resources, the default-resources execution of the resources plugin runs the goal copy-resources, which overrides your filtered resources again in the unfiltered state.
If you really want to do it this way, put the resources into a different directory than src/main/resources, change the phase of of the execution to somewhat appropriate (as to not confuse) and please also change the id of the execution (to something like copy-specially-filtered-resource - the id can be used to explain why there is the need for a second execution)
Also, the output directory is wrong (would need to be: ${project.build.outputDirectory}, directory points only to the target folder.
<build>
<finalName>my-app</finalName>
<filters>
<filter>${basedir}/src/main/properties/base.properties</filter>
</filters>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-special-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<useDefaultDelimiter>false</useDefaultDelimiter>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<resources>
<resource>
<directory>
${basedir}/src/main/filtered
</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Also, in this case, I would place the filters into the execution configuration as well (everything else is misleading).
Preferred: Simply reconfigure the resources plugin
Way shorter and easier would be to simply reconfigure the resources plugin, activate filtering for the resources globally and use the default execution (however, this would also be active for test-resources):
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<finalName>my-app</finalName>
<filters>
<filter>${basedir}/src/main/properties/base.properties</filter>
</filters>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<useDefaultDelimiter>false</useDefaultDelimiter>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
Hint: Using the override config is usually a smell...
First why not reading the documentation of maven-war-plugin
Based on the documentation you can define a configuration to use a supplemental directory and activate filtering for that directory like this:
<configuration>
<filters>
<filter>properties/config.prop</filter>
</filters>
<nonFilteredFileExtensions>
<!-- default value contains jpg,jpeg,gif,bmp,png -->
<nonFilteredFileExtension>pdf</nonFilteredFileExtension>
</nonFilteredFileExtensions>
<webResources>
<resource>
<directory>resource2</directory>
<!-- it's not a good idea to filter binary files -->
<filtering>false</filtering>
</resource>
<resource>
<directory>configurations</directory>
<!-- enable filtering -->
<filtering>true</filtering>
<excludes>
<exclude>**/properties</exclude>
</excludes>
</resource>
</webResources>
</configuration>
I would recommend to make a supplemental directory like src/main/filtered-resources which you configure to do filtering and the default resources directory I wouldn't change (no filtering by default). This makes it easier to understand.
If you want to change the delimiters you can add the configuration to the maven-war-plugin like this:
<delimiters>
<delimiter>#</delimiter>
</delimiters>
So in the end there is no need to make supplemental configuration for maven-resources-plugin etc.

How to do MAVEN filtering in this case?

I have maven project which contains Java classes and Windows/Linux scripts. Whenever I made some changes to the Java source code, I then execute 'mvn install' and call those scripts to test my changes. Those scripts therefore points to Maven repository to find the JARs. For instance,
SET app=%M2_REPO%\A\B\C\1.0-SNAPSHOT\C-1.0-SNAPSHOT.jar
SET app1=%M2_REPO%\E\F\G\1.0-SNAPSHOT\G-1.0-SNAPSHOT.jar
java -classpath !app!;!app1!;!app2!;!app3! !main_class! %1 %2 %3 %4
Now, the requirement is to
1. package all the jars and scripts into one ZIP file;
2. jars and scripts have to be at the root level in this ZIP file.
I just wonder if it is possible to automatically set app at
app=%M2_REPO%\A\B\C\1.0-SNAPSHOT\C-1.0-SNAPSHOT.jar
at compile phase
and automatically change it to
app=C-1.0-SNAPSHOT.jar
at install phase.
If yes then how? Thanks in advance.
You should use maven-resources-plugin with two separate setting files at two different phases:
<executions>
<execution>
<id>compile-settings</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>something</directory>
<filtering>true</filtering>
</resource>
</resources>
<filters>
<filter>resources/compile.properties</filter>
</filters>
</configuration>
</execution>
<execution>
<id>package-settings</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>something</directory>
<filtering>true</filtering>
</resource>
</resources>
<filters>
<filter>resources/package.properties</filter>
</filters>
</configuration>
</execution>
</executions>

build-helper-maven-plugin add-test-resource error

I have this project structure:
/src
/main
/java
/resources
/test
/java
/resources
/it
/java
/resources
test for unit tests and it for integration tests. I'm using build-helper-maven-plugin to add additional test sources/resources to the classpath for later use maven-surfire-plugin for run
unit tests and maven-failsafe-plugin for integration tests.
Plugin config as belows:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>add-integration-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/it/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-integration-test-resources</id>
<phase>generate-test-resources</phase>
<goals>
<goal>add-test-resource</goal>
</goals>
<configuration>
<resources>
<directory>/src/it/resources</directory>
</resources>
</configuration>
</execution>
</executions>
</plugin>
This works fine for the test-sources (they are coppied correctly to /target/test-classes) but doesn't copy test-resources. I've tried different combinations of <configuration>: use <resource> instead <directory>, use an specific file instead a directory...but neither works.
Stacktrace with the error:
Caused by: org.apache.maven.plugin.PluginConfigurationException: Unable to parse configuration of mojo org.codehaus.mojo:build-helper-maven-plugin:1.9.1:add-test-resource for parameter directory: Cannot configure instance of org.apache.maven.model.Resource from src/it/resources
at org.apache.maven.plugin.internal.DefaultMavenPluginManager.populatePluginFields(DefaultMavenPluginManager.java:597)
at org.apache.maven.plugin.internal.DefaultMavenPluginManager.getConfiguredMojo(DefaultMavenPluginManager.java:529)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:92)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
PROVISIONALLY, I've fixed it adding the integration tests resources to maven <build> configuration:
<build>
...
<testResources>
<testResource>
<directory>src/it/resources</directory>
</testResource>
</testResources>
</build>
But I would prefer to have centralized all classpath modifications under build-helper-maven-plugin.
Can anyone post example with a correct config?
Thanks in advance.
According to the javadoc of the maven-build-helper-plugin:add-test-resources. The resources is an array of org.apache.maven.model.Resource. Thus you must configure it this way:
<configuration>
<resources>
<resource>
<directory>/src/it/resources</directory>
</resource>
</resources>
</configuration>
Take a look at how to configure plugin parameters.

Categories