Specify common resources in a multi-module maven project - java

Is there any way to share resources between modules of a parent project in Maven? For example, I would like to specify one log4j.properties file for all the modules in a multi-module Maven project.
Generally, I use Eclipse IDE to create the parent project by choosing a general project and then convert it to a Maven project by specifying a packaging of pom. This creates a "clean" project structure without src and etc. folders. I wonder where such a shared resource should be put in this case.
EDIT1: I would like to put the common resources in the parent project.

I'd create one additional "base" module (project), packaging "jar", that contains the common resources in src/main/resources. Then I'd make the other modules depend on that project. Now they see the common resources on their classpaths.

Antoher possibility is to use a remote resource bundle. You would be able to configure it in the parent project. In this example I wanted to copy some files just for tests. If you use this you will need to create the bundle in another project.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.5</version>
<configuration>
<resourceBundles>
<resourceBundle>es.sca:myBundle:1.0.0</resourceBundle>
</resourceBundles>
<attachToMain>false</attachToMain>
<attachToTest>true</attachToTest>
<appendedResourcesDirectory>${basedir}/src/test/resources</appendedResourcesDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>

Another way, put in your project root pom:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<!-- don't propagate to child poms -->
<!-- this will only execute in root pom -->
<inherited>false</inherited>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<!-- don't add classifier -->
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugins>
And example of assembly.xml
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>resources</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/resources/</directory>
<outputDirectory/>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>**</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Assembly plugin will generate artifact and attach it to current reactor, so it will be installed and deployed.
No you can use it as standard dependency event in the same pom.
Important is to trigger assembly (proper phase) before another plugin which will use generated artifact.
Eg. You can have in your root pom, bellow configuration will be propagated to all your module:
<plugin>
<artifactId>some-maven-plugin</artifactId>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>goal</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>your.project.groupid</groupId>
<artifactI>your.project.artifactId</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
You can see this method in project:
https://github.com/s4u/pgp-keys-map resources directory is shared by all module.

Yes, it seems as a possible solution. But I was interested whether it
is possible to specify these resources in the parent project (without
introducing additional module) since the parent project specifies all
the common dependencies and Maven configurations for the child
modules, I think that the parent project is the most suitable place
also for the common resources.
In case of packaging type pom , when goal package specified to manage your shared resources, just add next (check folders) into build section of pom file :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-config-files</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/logconfig</outputDirectory>
<resources>
<resource>
<filtering>false</filtering>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

I think you can just add the resources and/or testResources elements to your pom.
E.g. to access an additional test resource directory add:
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
<testResource>
<directory>../global/src/test/resources</directory>
</testResource>
</testResources>
see Maven - Override test resource folder

I managed it to work like this:
I create a project/assembly/test/resources/META-INF/persistence.xml file, and add this to my pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-test-persistence-xml-resources</id>
<phase>process-test-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/</outputDirectory>
<resources>
<resource>
<directory>${project.parent.basedir}/assembly/</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

Related

Maven - How to include single java files as sources/depedencies

I have created a multi-module project in maven which is as follows:
root/pom.xml
|________client/pom.xml
|________/src/main/java
|________/src/main/resources
|________common/pom.xml
|________/src/main/java
|________tools/pom.xml
|________/src/main/java
|________server/pom.xml
|________/src/main/java
|________/src/main/resources
I would like to compile the "client" module code which depends on ALL java classes in "common" module but on SOME java classes in the "tools" module.
Using the build-helper-maven-plugin as below, I was able to add all java source files under common/ path, but I need a way to define individual java files as sources which are under tools/.
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>../common/src/main/java</source>
<!-- Adding single java files as below does not work -->
<source>../tools/log/Log.java</source>
<source>../tools/socket/SocketClient.java</source>
<!----------------------------------------------------->
</sources>
</configuration>
</execution>
</executions>
You should include module "common" and "tools" as dependency in "client"
Then you can run build in the root of project: mvn clean install - it will build all modules.
Don't try to use parts of a module as dependency. Maven does not support this and it results in brittle and hard to maintain constructions.
If you only need parts of tools, then this is a clear signal that tools is too large and you need to split it up into two modules.
Ok, based on the comments received it seems that the ideal solution is to break the modules into sub-modules and use those as dependencies. However, as this is currently a time consuming task, I am posting a quick and dirty solution on how you can include one or more java files into your build by copying the files under a new source directory, src/main/external, and then add this directory as part of your sources.
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-source-java-files</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/external</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<!-- External source directory -->
<directory>../tools/src/main/java/</directory>
<includes>
<!-- Files to be copied along with their directory paths -->
<include>tools/log/Log.java</include>
<include>tools/socket/SocketClient.java</include>
<include>tools/client/reader/**</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/java</source>
<source>src/main/resources</source>
<source>../common/src/main/java</source>
<!-- Here we add the source with the files copied -->
<source>src/main/external</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The output after compilation would be as follows:
root/pom.xml
|________client/pom.xml
|________/src/main/java
|________/src/main/resources
|________/src/main/external <----- This contains all external java files.

how to create multiple jars with usage specific xml copied to jar - Maven

I am trying to migrate from ANT build to Maven build setup for a very simple codebase setup:
src > Java Classes
conf > META-INF > 3 xml files namely dbConnect-jboss.xml, dbConnect-weblogic.xml, dbConnect-ooc.xml
The goal is to create 3 JARs :
project-jboss.jar, project-weblogic.jar, project-ooc.jar
where each jar will have META-INF/dbConnect.xml, copy of relevant conf/META-INF/dbConnect-xxx.xml.
I tried with [maven-jar-plugin + maven-antrun-plugin ] but the issue is the maven-antrun-plugin does the copy only one time so suppose project-jboss.jar created first then all the rest jars will have same dbConnect.xxx.xml
I need to get a way - how to invoke the copy of dbConnect.xml file via maven-antrun-plugin each time for the respective JAR creation.
screenshot for maven-ant and maven-jar plugin section from pom.xml
Thanks for all those who tried to help me out here, appreciate your helping gesture.
I opted maven-assembly-plugin for the needful.
The following snippet would explain my approach:
<pluginManagement>
<plugins>
<plugin>
<!-- To suppress default JAR creation -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-jar</id>
<phase />
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<finalName>${project.artifactId}</finalName>
<useProjectArtifact>false</useProjectArtifact>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
<executions>
<execution>
<id>create-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
Then I created respective assembly xml files for each relevant JAR expected. For example, one of assembly xmls:
<assembly ....>
<id>jboss</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<!-- Avoid getting relevant dependencies included in JAR -->
<includes>
<include>com.vibrant:streamliner.reposerv</include>
</includes>
<useTransitiveDependencies>false</useTransitiveDependencies>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>META-INF/**</exclude>
</excludes>
</unpackOptions>
</dependencySet>
</dependencySets>
<files>
<file>
<source>${project.basedir}/config/META-INF/dbConnect-jboss.xml</source>
<outputDirectory>META-INF</outputDirectory>
<destName>dbConnect.xml</destName>
</file>
</files>
Then, I added profile in pom.xml:
<profile>
<id>create-all-jars</id>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>pom-assembly-jboss.xml</descriptor>
<descriptor>pom-assembly-weblogic.xml</descriptor>
<descriptor>pom-assembly-ooc.xml</descriptor>
</descriptors>
<appendAssemblyId>true</appendAssemblyId>
</configuration>
</plugin>
</plugins>
</build>
</profile>
And, once we execute following - 3 Jars get created:
mvn -P create-all-jars clean package

How to make Eclipse recognize folders as "code folders" when a project is imported?

I have a Maven Java project in which I added to the pom:
<build>
....
<plugin>
<!-- adding second test source directory (just for integration tests) -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${plugin.build-helper-maven-plugin.version}</version>
<executions>
<execution>
<id>add-integration-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/integration-test/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-integration-test-resource</id>
<phase>generate-test-resources</phase>
<goals>
<goal>add-test-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/integration-test/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</build>
InteliJ recognized my java and resource folders under integration-test as a code folder, but Eclipse doesn't.
Is there any way that eclipse adds these folders as code folders when the project is imported?
Try to right click on your folder in Project Explorer select Build Path option in context menu and later click Use as Source Folder in menu which appears after choosing Build Path.
I suggest not using your own directory layout with Maven since this will cause many problems and you always have to configure around it. Just stick to the standard.
Separate integration tests and unit tests not by their source folders, but by their name.
Put all tests in src/test/java. You don't have to configure anything at this point, this path is taken by default.
Call integration tests IT*.java and unit tests UT*.java.
They can be run separately because maven-surefire-plugin executes unit tests and maven-failsafe-plugin executed integration tests. You can define filename patterns for identifying the test classes.
You could also create profiles for running only UTs or only ITs.
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<includes>
<include>**/UT*.java</include>
</includes>
<excludes>
<exclude>**/IT*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18</version>
<configuration>
<includes>
<include>**/IT*.java</include>
</includes>
</configuration>
<executions>
<execution>
<id>failsafe-integration-tests</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
Further reading: http://tomaszdziurko.pl/2013/01/running-unit-tests-integration-tests-separately-maven-testng/
There is also a interesting article about the correct usage of integration tests here: http://zeroturnaround.com/rebellabs/the-correct-way-to-use-integration-tests-in-your-build-process/

How to protect auto-generated sources during clean package in maven?

I have a maven config file that triggers autogeneration of xsd and wsdl classes as follows:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-xjc-plugin</artifactId>
<version>${cxf-xjc-plugin}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/src/main/java</sourceRoot>
<xsdOptions>
//xsds, wsdls etc
</xsdOptions>
</configuration>
<goals>
<goal>xsdtojava</goal>
</goals>
</execution>
</executions>
</plugin>
The generated classes go to: target/generated/src/main/java.
Problem: running 'mvn clean package' will always remove those classes. How can I prevent it? Is it possible having clean remove the full content of the target directory apart from the generated/ one?
It is possible not to delete some directory using maven-clean-plugin but this is definitely not a good idea:
it goes against Maven conventions
it forces you to change your POM everytime you want those classes to be generated
Solution to your exact question (NOT RECOMMENDED)
You can exclude directories with the maven-clean-plugin using excludeDefaultDirectories and filesets parameters:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6.1</version>
<configuration>
<excludeDefaultDirectories>true</excludeDefaultDirectories>
<filesets>
<fileset>
<directory>${project.build.directory}</directory>
<excludes>
<exclude>generated/*</exclude>
</excludes>
</fileset>
</filesets>
</configuration>
</plugin>
Note that I strongly urge you NOT to use this solution.
Proposed solution
Your actual problem is not to re-generate the classes everytime you build because it takes a lot of time. The goal is then to avoid generation by using a custom profile:
<profiles>
<profile>
<id>noGenerate</id>
<properties>
<xjc.generate>none</xjc.generate>
</properties>
</profile>
<profile>
<id>generate</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<xjc.generate>generate-sources</xjc.generate>
</properties>
</profile>
</profiles>
With the following plugin definition:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-xjc-plugin</artifactId>
<version>${cxf-xjc-plugin}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>${xjc.generate}</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/src/main/java</sourceRoot>
<xsdOptions>
//xsds, wsdls etc
</xsdOptions>
</configuration>
<goals>
<goal>xsdtojava</goal>
</goals>
</execution>
</executions>
</plugin>
It seems cxf-xjc-plugin does not have any skip parameter so we have to resort to setting the phase to none when we want to avoid execution (this is an undocumented feature but it works).
The trick is to define two profiles: one, activated by default, sets a property telling the cxf-xjc-plugin to execute in the generate-soures phase, while the other one sets a property telling the cxf-xjc-plugin not to execute.
As such, when you want to classes to be generated, you can invoke Maven with mvn clean install and when you want the classes not to be generated, you can invoke Maven with mvn clean install -PnoGenerate.
The real gain and advantage here is that you do not need to change your POM everytime you decide to generate or not the classes.
I would have another approach.
1st) Configure your xjc plug-in to not erase any files i.e.:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<clearOutputDir>false</clearOutputDir>
<outputDirectory>${project.build.directory}</outputDirectory>
<sources>
<source> [any xsd] </source>
</sources>
</configuration>
2nd) Use maven-clean-plugin to clean jxc class generated dir in clean stage:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<filesets>
<fileset>
<directory>${basedir}/generated/src/main/java/...where the generated classes are</directory>
<includes>
<include>**/*.java</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
This works for me and I hope would be useful.

How to add multiple .properties files as build artifacts with Maven?

I have a Maven project where I want to have two build artifacts:
The jar file containing the compiled Java source.
A folder containing a number of .properties file.
How can I setup my Maven project to do this? And then, once I've done this, how can I consume them up the dependency graph?
Add a copy-resources goal of the Maven Resources Plugin to your POM.
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-property-files</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/property-files</outputDirectory>
<resources>
<resource>
...
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
...
</project>
I can't understand what you mean exactly by "consume them up the dependency graph".

Categories

Resources