Maven changes the order of plugins of different profiles - java

I have a pom.xml where I define the same plugin (same groupId and artifactId, different execution :-) ) in two different profiles. The executions are defined in the same phase, so the order is calculated by the order from the xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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>echo</groupId>
<artifactId>test</artifactId>
<name>echo-test</name>
<version>1.0.0</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>1st-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>1st-antrun-echo</id>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>1st antrun plugin</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>2nd-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.soebes.maven.plugins</groupId>
<artifactId>maven-echo-plugin</artifactId>
<version>0.1</version>
<executions>
<execution>
<id>1st-soebes-echo</id>
<phase>test</phase>
<goals>
<goal>echo</goal>
</goals>
<configuration>
<echos>
<echo>1st echo-plugin</echo>
</echos>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>2nd-antrun-echo</id>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>2nd antrun plugin</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
All the plugin executions are defined in the test phase, therefore I would expect the following order:
1st antrun plugin
1st echo-plugin
2nd antrun plugin
However, since the antrun-plugins are merged, I get this output:
1st echo-plugin
1st antrun plugin
2nd antrun plugin
This command explains why is this happening: mvn help:effective-pom
Is there any other solution to preserve the order other than to introduce a new phases? Our project is really big and this is a very simplified example.
Why is this limitation of maven to merge the plugins into one with multiple executions?

In my experience this is one of the biggest bugs in Maven. If you have more than one configuration for the same plugin in different profiles, the order is simply unpredictable. I even observed, that I had some plugin order in project B in a given phase, and as soon as some of the same plugins got a config in a parent project (not even in the same phase), the order was ruined.
There is an obviously falsely closed bug related to this at https://issues.apache.org/jira/browse/MNG-2258.
Possible workarounds
Try to shift some of the plugins to previous phase if possible
(prepare-test used for some of the plugins and test for the rest)
Try
to replace the functionality of multiple plugins with a
groovy-maven-plugin script (quite handy with the ant integration, and
you reach the list of the active profiles in the script)
Write your
own mojo and call the plugins in the correct order (See
https://github.com/TimMoore/mojo-executor)
Give a try to gradle. Maybe it fits your needs, and it comes with a lot of good things from Maven
I do not think that there is any more you can do right now.

Related

Running groovy-maven-plugin within POM packaged project

I want to run groovy scripts as part of parent POM which has POM packaging.
I set maven-groovy-plugin configured as follows:
<groupId>org.sct</groupId>
<artifactId>app-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>app</name>
<modules>
<module>module1</module>
<module>module2</module>
<module>module3</module>
</modules>
...
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>execute</goal>
</goals>
</execution>
</executions>
<configuration>
<source>${project.basedir}/src/test/groovy/check-xsl-id.groovy</source>
</configuration>
</plugin>
...
However the script is not executed during the build.
If I run the goal individually mvn groovy:execute it works fine.
How can I bind plugin execution to a POM packaging phase?
Using <plugin> instead of <pluginManagement> for plugin configuration works perfectly well.

How to fix "org.apache.velocity.exception.ResourceNotFoundException" during schema generating

I am trying to integrate avro maven plugin into my application. I was forced to use custom templates because of Avro limitations.
When I include that plugin into build it fails (on windows, not unix) with exception:
[ERROR] Failed to execute goal org.apache.avro:avro-maven-plugin:1.9.1:schema (schemas) on project cloud-poc: Execution schemas of goal org.apache.avro:avro-maven-plugin:1.9.1:schema failed: org.apache.velocity
.exception.ResourceNotFoundException: Unable to find resource 'C:\..........\cloud-microservices\cloud-poc/src/main/resources/avro/templates/record.vm'
But when I do cat C:\..........\cloud-microservices\cloud-poc/src/main/resources/avro/templates/record.vm from PowerShell then it prints the file - it can find it.
The configuration works on unix systems without any issues. Here is pom:
<?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.....</groupId>
<artifactId>cloud-poc</artifactId>
<version>0.8.0</version>
<packaging>jar</packaging>
<name>cloud-poc</name>
<description>Proof of concept microservice</description>
<properties>
<kafka.version>2.2.8.RELEASE</kafka.version>
</properties>
<dependencies>
.... avro + kafka
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>schemas</id>
<phase>generate-sources</phase>
<goals>
<goal>schema</goal>
<goal>protocol</goal>
<goal>idl-protocol</goal>
</goals>
<configuration>
<sourceDirectory>${project.basedir}/src/main/resources/avro</sourceDirectory>
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
<fieldVisibility>PRIVATE</fieldVisibility>
<stringType>String</stringType>
<createSetters>false</createSetters>
<templateDirectory>${project.basedir}/src/main/resources/avro/templates/</templateDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I also tried to use ablsoute path, different maven variables and relative path. I tried it on few projects, without luck.
I would expect the classes to be generated instead of.
The root of problem is about how velocity looking for a templates using a file path. In another hand, classpath lookup have issues with maven plugin classpath. At the moment I was able to fix this in a two ways: using classpath resource and using file resource.
Solution 1: Using a classpath.
Since you already have you templates in resourources, it will be copied to classpath and you may refers to it once it copied to target/classes.
Change templateDirectory to refer classpath resource, and change phase of avro-plugin execution to be after resources copied:
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>schemas</id>
<phase>process-resources</phase>
<goals>
<goal>schema</goal>
<goal>protocol</goal>
<goal>idl-protocol</goal>
</goals>
<configuration>
<sourceDirectory>${project.basedir}/src/main/resources/avro</sourceDirectory>
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
<fieldVisibility>PRIVATE</fieldVisibility>
<stringType>String</stringType>
<createSetters>false</createSetters>
<templateDirectory>/avro/templates/</templateDirectory>
</configuration>
</execution>
</executions>
</plugin>
Solutuion 2: Using a relative path.
You must refers to a template directory, using the relative path from project root. At the moment, I'm not sure would it work properly for multimodular maven project or not.
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>schemas</id>
<phase>generate-sources</phase>
<goals>
<goal>schema</goal>
<goal>protocol</goal>
<goal>idl-protocol</goal>
</goals>
<configuration>
<sourceDirectory>${project.basedir}/src/main/resources/avro</sourceDirectory>
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
<fieldVisibility>PRIVATE</fieldVisibility>
<stringType>String</stringType>
<createSetters>false</createSetters>
<templateDirectory>/src/main/resources/avro/templates/</templateDirectory>
</configuration>
</execution>
</executions>
</plugin>
You can use profiles by OS family.
Add to your pom:
<profiles>
<profile>
<id>Windows</id>
<activation>
<os>
<family>Windows</family>
</os>
</activation>
<properties>
<avro.template.dir>src/main/resources /avro/templates/</avro.template.dir>
</properties>
</profile>
<profile>
<id>unix</id>
<activation>
<os>
<family>unix</family>
</os>
</activation>
<properties>
<avro.template.dir>${basedir}/src/main/resources /avro/templates/</avro.template.dir>
</properties>
</profile>
</profiles>
And then set templateDirectory to ${avro.template.dir}

Creating jars for Maven repository, how?

Googled this question but no straight answer was found sadly.
So, I have a Maven project. I want to upload my release to Maven Central Repository. This means I need to create 3-4 jar files:
Compiled source jar
Javadoc jar
Source code jar
Tests jar (optional)
How can I create all these jars? Add some configuration to POM?
BTW, I am using latest Netbeans IDE, but this shouldn't matter :)
Any help is appreciated!
EDIT
So this is my POM:
<?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.company</groupId>
<artifactId>sdk</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.5.3</version>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Maven can create these jars for your. Next to 1,2,3,4 you will also need to sign your release artifacts. To get the artifact into maven central I would advise you to read:
The official Maven guide to get your artifact into maven central
The guide from the Open Source Sonatype repository. It contains all the information you will need to know.
With regards to your pom.xml you can add a separate release profile, which builds all these artifacts for you.
Just add the following profile to your pom.xml
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Now when you want to create the release you can just call:
mvn clean install -Prelease
and it will create all the required artifacts.
Take a look at this guide and this. You need to raise a ticket for a mirror repository of your choice, then you need to use additionally plugins for signing jar, generating documents, adding source and doing remote deployment for you.

How to use Maven Exec Plugin as Library in another plugin?

I currently am using the Exec Maven Plugin and it works fine with:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>myExec</id>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<executable>myExec</executable>
<arguments>
<argument>--foo=${basedir}/src/test/resources/test.xml</argument>
<argument>--output-directory=target/generated-sources/output</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
I am also using the build helper plugin as follows:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/output</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
This is incredibly verbose however and I want multiple maven modules to be able to use this program and not have to retype all the exec plugin specific XML along with the builder XML.
Question: How do I possibly combine these 2 into another plugin?
I have used the maven archetype generator to generate a sample maven plugin and have a Mojo class:
#Mojo(name = "touch", defaultPhase = LifecyclePhase.PROCESS_SOURCES)
public class MyMojo
extends AbstractMojo
{
public void execute()
throws MojoExecutionException
{
ExecMojo exec = new ExecMojo();
}
}
And have figured out how to create a new ExecMojo.
Question How do I add the arguments here as I would in the XML above? And how can I integrate these arguments into my plugin?
Instead of creating your own Maven plugin, which may reduce portability and maintenability of your project, you may consider the following approach instead:
Have a common parent pom
Configure the given plugins configuration, optionally in a Maven profile
In the concerned module, point to this parent. Optionally (in case of profiled configuration) activate it on demand when required.
A simple parent pom would look like the following:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>sample-maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<path.to.myexec>path</path.to.myexec>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>myExec</id>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<executable>${path.to.myexec}\myExec</executable>
<arguments>
<argument>--foo=${basedir}/src/test/resources/test.xml</argument>
<argument>--output-directory=${project.build.directory}/generated-sources/output</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/output</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>myexec-profile</id>
<build>
<plugins>
<!-- optionally move here the configuration above -->
</plugins>
</build>
</profile>
</profiles>
</project>
Note the path.to.myexec property I added, to be overriden in children projects if required, in order to point to the correct relative path.
Then, once installed in your machine (or deployed in your company Maven repository), it can be referenced as following in any concerned Maven projects:
<parent>
<groupId>com.sample</groupId>
<artifactId>sample-maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
No need to re-declare the plugin configurations above and its verbose approach. They will be automatically part of the defaul build as part of the inherited build configuration from this parent.
The profiled approach can also be a solution if:
You want to reuse an existing parent pom already used by projects which don't need this configuration
You don't always need this behavior on your build and you want to activate it on demand
In such a case, you can then activate it via, as an example:
mvn clean package -Pmyexec-profile
Given that you already set the parent accordingly and you moved into the profile the configuration above.
Advantages of this approach:
lighter option than writing a new maven plugin (which needs to be written, tested, maintained, distributed, etc.)
easier for consumer modules to customize something: at any moment they can override parent's configuration as an exception
less fragile: just imagine what if another version of one of these plugins provides a bug fix important for you, that's easy to configure an XML, much less easy to change the customized maven plugin etc.
configuration remains centralized, transparently accessible and entry point for further governance
easier troubleshooting: at any moment a consumer module can run mvn help: effective-pom and see the merged full effective pom (as aggregate of parent and current pom) and check what it's actually running
How to skip parent plugin executions in certain modules
A simple (and often used) approach to execute this plugins only in certain modules while having the parent in common with other modules is the following:
Define a new property, let's call it skip.script.generation, with default value to true, defined in the parent pom.
Use this skip property in the skip configuration entry of the plugins above.
Re-define the property only in the concerned modules and set it to false. This will be the only configuration required for their pom.xml files, hence reduced to one line (keeping verbosity really low).
The exec-maven-plugin provides such a skip option, unfortunately the build-helper-maven-plugin doesn't. But that's not blocking us. We can still skip the two executions playing with their phase element, setting it to a non existing phase, like none and as such skipping them. This is suitable because the two executions are actually already attached to the same phase, generate-sources.
For this approach, let's rename our new property to script.generation.phase.
As an example:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>sample-maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<path.to.myexec>path</path.to.myexec>
<script.generation.phase>none</script.generation.phase>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>myExec</id>
<goals>
<goal>exec</goal>
</goals>
<phase>${script.generation.phase}</phase>
<configuration>
<executable>${path.to.myexec}\myExec</executable>
<arguments>
<argument>--foo=${basedir}/src/test/resources/test.xml</argument>
<argument>--output-directory=${project.build.directory}/generated-sources/output</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<phase>${script.generation.phase}</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/output</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>myexec-profile</id>
<build>
<plugins>
<!-- optionally move here the configuration above -->
</plugins>
</build>
</profile>
</profiles>
</project>
Note the <phase>${script.generation.phase}</phase> changes for both plugins. With its default value to none, this property is effectively disabling their executions by default.
In another module you would then have the following:
<parent>
<groupId>com.sample</groupId>
<artifactId>sample-maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<script.generation.phase>generate-sources</script.generation.phase>
</properties>
And nothing else. That is. Maven during the build will re-define the property for a certain module and automatically replace it in the configuration inherited from its parent and as such enabling again the two executions above.

Maven profiles are not inherited in child modules

I'm trying to separate different kinds of tests (unit, integration, acceptance) by using maven profiles. This is the part of the main pom file:
<properties>
<build.profile.id>dev</build.profile.id>
<skip.unit.tests>false</skip.unit.tests>
<skip.integration.tests>true</skip.integration.tests>
<skip.acceptance.tests>true</skip.acceptance.tests>
</properties>
<profiles>
<profile>
<id>dev</id>
</profile>
<profile>
<id>integration-test</id>
<properties>
<build.profile.id>integration-test</build.profile.id>
<skip.unit.tests>true</skip.unit.tests>
<skip.integration.tests>false</skip.integration.tests>
<skip.acceptance.tests>true</skip.acceptance.tests>
</properties>
</profile>
<profile>
<id>acceptance-test</id>
<properties>
<build.profile.id>acceptance-test</build.profile.id>
<skip.unit.tests>true</skip.unit.tests>
<skip.integration.tests>true</skip.integration.tests>
<skip.acceptance.tests>false</skip.acceptance.tests>
</properties>
</profile>
</profiles>
<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<skipTests>${skip.unit.tests}</skipTests>
<includes>
<include>**/*UnitTests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.17</version>
<executions>
<execution>
<id>integration-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<skipTests>${skip.integration.tests}</skipTests>
<includes>
<include>**/*IntegrationTests.java</include>
</includes>
</configuration>
</execution>
<execution>
<id>acceptance-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<skipTests>${skip.acceptance.tests}</skipTests>
<includes>
<include>**/*AcceptanceTests.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
As you can see I'm using the profile information to run certain types of tests based on the profile that is used. Default profile is dev and it will only run unit tests. They can be executed like this:
mvn clean test
For integration and acceptance tests I use failsafe plugin: Example of running integartion tests would be:
mvn clean verify -P integration-test
This works fine when I run it from the main pom module, but it doesn't work when running it from the child module. Tests are just ignored. Looking at the effective pom for child module I don't see the profiles. Am I doing something wrong or is this is expected behavior from maven? If profile inheritance (needs to cascade to deepest modules in the hierarchy) can't be achieved this way how can it be done?
Update: This is the project hierarchy
project directory
--main module
--commons module
--administration
----domain
----data
----business
----web
With multimodule project you usually don't execute modules directly. Instead you should always execute the main module, but specify only your desired submodule via -pl parameter. There are a lot more issues connected with running modules directly.
Just double checked some multi-module projects I have participated on and I we are using <pluginManagement> to propagate plugin configuration form parent POM to child projects.

Categories

Resources