How does maven decide when to use the target folder for classpath - maven

I have a question regarding how maven calculates the classpath during building. Specifically, what controls when the "target/classes" is used and when the "jar" from a repository (local/remote) is used.
I have a project on version 1.0.0-SNAPSHOT where the artifacts have NOT been installed/deployed so there is no "jar" in some repository (remote or local) to resolve them. I want to run "generate-sources" WITHOUT installing locally (no 'mvn install' run).
The structure looks like this:
parent-prj
parent-prj/sub-prj
parent-prj/gen-src-prj <--- This depends on 'sub-prj'
When I run "mvn -am -pl parent-prj/gen-src-prj generate-sources" in order to just generate some java files, it does not work:
[ERROR] Failed to execute goal on project gen-src-prj: Could
not resolve dependencies for project
mygrp:gen-src-prj:jar:1.0.0-SNAPSHOT:
Could not find artifact
mygrp:sub-prj:jar:1.0.0-SNAPSHOT -> [Help 1]
Using debug output and adding "dependency:build-classpath" I can confirm that maven ignores the presence of "sub-prj" in the reactor and looks for a "jar" somewhere which it can't find. Yet the project is printed in the reactor summary:
[INFO] Reactor Summary:
[INFO]
[INFO] parent-prj ..................................... SUCCESS [ 0.625 s]
[INFO] sub-prj ........................................ SUCCESS [ 0.018 s]
[INFO] gen-src-prj .................................... FAILURE [ 0.040 s]
The interesting thing I noticed is that running the compile goal works fine! This uses sub-prj/target/classes (as shown by dependency:build-classpath) and has no trouble generating the sources and even compiling them: "mvn -am -pl parent-prj/gen-src-prj compile"
So here are the points I want to understand:
Why does the compile goal work but the generate-sources doesn't work?
At what point does maven decide to use the output folder of previous projects on the reactor classpath instead of looking for a jar?
Is there a way for generate-sources to run directly as I want it EVEN WITHOUT having its dependencies resolved?
Regarding (3) my generation tool is a utility invoked by:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
The tool reads some XML in src/main/resources and generates Java files and does NOT need anything in its class-path (so there is no need for maven to resolve it).
Also note that I would be interested to understand (1) and (2) even if a solution for (3) is provided.
EDIT: Per comment request, adding full example
parent-prj/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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mygrp</groupId>
<artifactId>parent-prj</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>sub-prj</module>
<module>gen-src-prj</module>
</modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.9</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
parent-prj/sub-prj/pom.xml
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>mygrp</groupId>
<artifactId>parent-prj</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>sub-prj</artifactId>
</project>
parent-prj/gen-src-prj/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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>mygrp</groupId>
<artifactId>parent-prj</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>gen-src-prj</artifactId>
<dependencies>
<dependency>
<groupId>mygrp</groupId>
<artifactId>sub-prj</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<includeProjectDependencies>false</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<mainClass>uk.co.real_logic.sbe.SbeTool</mainClass>
<systemProperties>
<systemProperty>
<key>sbe.output.dir</key>
<value>${project.build.directory}/generated-sources/java</value>
</systemProperty>
<systemProperty>
<key>sbe.validation.warnings.fatal</key>
<value>true</value>
</systemProperty>
</systemProperties>
<arguments>
<argument>${project.build.resources[0].directory}/Examples.xml</argument>
</arguments>
<workingDirectory>${project.build.directory}/generated-sources/java</workingDirectory>
</configuration>
<dependencies>
<dependency>
<groupId>uk.co.real-logic</groupId>
<artifactId>sbe-tool</artifactId>
<version>1.7.10</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-sources/java/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
EDIT: Armed with the knowledge from the answers I have come up with this workaround that allows one to achieve the desired behaviour. I list the dependencies in a profile that is active by default, then use another profile to run generate-sources with no dependencies active, like follows:
parent-prj/gen-src-prj/pom.xml
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>mygrp</groupId>
<artifactId>sub-prj</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>excludeDependency</id>
<dependencies>
</dependencies>
</profile>
</profiles>
To generate sources with above, use: mvn -PexcludeDependency generate-sources

Maven can reference only output generated in current Session (during currently executing shell command). It uses the most "mature" place to look for the "output":
If compile is run - the classes end up in the target/classes dir, thus other modules can reference that
If package is run - then target/*.jar is created and this jar file ends up in the classpath instead
If install is run - then jar file ends up in the local repository - which is what ends up on the classpath
So there are 3 factors that impede your task:
maven-exec-plugin requires dependency resolution (as pointed out by #mondaka)
Your module1 references module2
generate-sources is run before the compilation. Thus module2 is not yet prepared to be used as a dependency.
So if you want to do it your way - you'll have to run at least compile phase each time you use anything from the Default Lifecycle. Or you could write your own plugin that doesn't require dependency resolution.

This problem is related to an open maven bug:
https://issues.apache.org/jira/browse/MNG-3283
The issue says: "The problem only occurs when a plugin binds itself to the
generate-sources phase and has #requiresDependencyResolution".
I have checked that exec-maven-plugin Mojo have indeed requiresDependencyResolution = ResolutionScope.TEST. You can see that on https://github.com/mojohaus/exec-maven-plugin/blob/master/src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java
Then, your only option is to use compile or process-classes phases. This is a Major open bug from 2007...

Related

Properties defined in the properties section of the POM are not seen in external ant build file

I'm using maven-antrun-plugin in my pom.xml with external ant file.
It's said in plugin's document:
All of the properties available to Maven are also available in the
target configuration. However, you may want to call an external Ant
build script using the ant task. To avoid name conflicts, only a
subset of the properties are passed to the external Ant build. These
include all properties defined in the properties section of the POM.
It also includes prefixed versions of some of the commonly used Maven
properties.
So here's my pom, where I define "test.prop" property:
<?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>testant</groupId>
<artifactId>testant</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<test.prop>TestPropValue</test.prop>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>ant</groupId>
<artifactId>optional</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>generate-index-properties</id>
<phase>install</phase>
<configuration>
<tasks>
<!--<property name="test.prop" value="${test.prop}"/>-->
<ant antfile="build.xml">
<target name="echo-prop"/>
</ant>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
And just trying to echo this property in build.xml:
<project default="test">
<target name="echo-prop">
<echo>${test.prop}</echo>
</target>
</project>
This is what I get:
echo-prop:
[echo] ${test.prop}
So property is not resolved as it should, according to the doc.
And it works fine only in case if I uncomment line with explicit property declaration under "tasks" tag.
Could you please help me in understanding, what am I doing wrong?
Thank you!
You should specify a version for the antrun-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version><!--$NO-MVN-MAN-VER$-->
(...)
</plugin>
ant by default passes all properties of the parent to an underlying "ant"-call. Unless you define inheritAll=false, all properties are passed.
In this case, you should have a look at the effective pom. There a very ancient version of the antrun-plugin is defined.
As soon as you switch to a recent one, the example code works.

copy jars used by plugin to single folder using Maven

In my POM.xml other the plugin configuration, i am not required to configure any dependenices to run the plugin. I would like to download dependent jars used by plugin(soapui-maven-plugin) from the repository into one single folder. I tried the command "mvn dependency:copy-dependencies", but no jars are copied. Is there any way to do it?
<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>service.report</groupId>
<artifactId>service-report</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Maven 2 SoapUI Sample</name>
<build>
<plugins>
<plugin>
<groupId>com.smartbear.soapui</groupId>
<artifactId>soapui-maven-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>loadtest</goal>
</goals>
<configuration>
<projectFile>${basedir}/src/main/resources/xxxxx-soapui-project.xml</projectFile>
<testSuite>xxxx</testSuite>
<testCase>sssss</testCase>
<loadTest>LoadTest 1</loadTest>
<outputFolder>${basedir}/target/surefire</outputFolder>
<junitReport>true</junitReport>
<exportAll>true</exportAll>
<printReport>true</printReport>
<testFailIgnore>false</testFailIgnore>
<!-- <projectProperties>
<value>message=Hello World!</value>
</projectProperties> -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
mvn dependency:copy-dependencies is only applied to current maven module only. It won't works on plugins. If you want to download all soapui-maven-plugin dependencies, you need to execute command from soapui-maven-plugin project. You can follow the following steps. I assumed you familiar with GIT CLI. If not, you need to manually download from https://github.com/SmartBear/soapui
git clone https://github.com/SmartBear/soapui
cd soapui/soapui-maven-plugin
mvn dependency:copy-dependencies
You can get list of dependencies in soapui/soapui-maven-plugin/target/dependency (total 82files)
[ERROR] Failed to execute goal on project soapui-maven-plugin: Could not resolve dependencies for project com.smartbear.soapui:soapui-maven-plugin:maven-plugin:5.0.0: Could not find artifact javafx:jfxrt:jar:2.2 at specified path (your jdk path)
If you get the above error, it means your maven jdk is version jdk.1.7 (u6 or earlier) which is not installed with javafx. Download newer jdk that comes with javafx at http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html . Remember change your maven jdk to this newer jdk.
If you want to use the dependency-plugin you could add the dependencies to the pom...and download with the depepndency-plugin...
It works right for me...
<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.ab.forge.utility.copydependenciespom</groupId>
<artifactId>copydependenciespom</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- BINARIES -->
<dependencies>
<!--CUSTOMER RETURN -->
<dependency>
<groupId>com.ab...</groupId>
<artifactId>customerret.....</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<overWriteIfNewer>true</overWriteIfNewer>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
<excludeGroupIds>com.ab.ah.scad.acl</excludeGroupIds>
<excludeTypes>pom</excludeTypes>
<includeGroupIds>com.ab.oneleo</includeGroupIds>
<outputDirectory>${outputDirectory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
After I just run the install passing the -DoutputDirectory parameter....
Try this...
To view all the plugin dependencies you can run a dependency:tree on the pom (where the plugin in configured)

Dependency management does not work for multi-module project

I have a Maven project with multiple modules and I'm trying to set it up so that module dependencies are automatically built to the correct lifecycle phase needed for building depending modules to the requested lifecycle phase.
In the example, the module plugin builds a Maven plugin, which is used to generate source code and is used by the module main. If I just try to use mvn -am -pl main compile, the module plugin is compiled but the process-classes lifecycle phase is not executed (which is necessary for a plugin to be usable). Compiling the module main then fails then with the following error:
[ERROR] Failed to parse plugin descriptor for example:plugin:1.0.0-SNAPSHOT (/Users/ims/Dropbox/IMS/Projects/PARITy_R4/codegen-test-simple/plugin/target/classes): No plugin descriptor found at META-INF/maven/plugin.xml -> [Help 1]
Is Maven, or a plugin for it, capable of resolving the dependencies of modules in a multi-module project and build them to stage necessary by other modules? And if so, how do I need to set up the project for this to work?
These are the POMs of my project:
pom.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>plugin</module>
<module>main</module>
</modules>
</project>
plugin/pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
<parent>
<groupId>example</groupId>
<artifactId>project</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.2</version>
<configuration>
<goalPrefix>configurator</goalPrefix>
</configuration>
<executions>
<execution>
<id>default-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
main/pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>main</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>example</groupId>
<artifactId>project</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>example</groupId>
<artifactId>plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>codegen</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
If you look at the reference documentation for the Maven lifecycle, you'll see that compile is before process-classes.
If you want this step to happen, you need to use mvn -am -pl main process-classes instead.
But I suggest that you always use mvn ... install - it also runs the tests and makes sure that the plugin which main uses is actually the one you think it should: Without install, the build will use an old/outdated version from the local repository (Maven will not magically determine "oh, there is a plugin in my reactor, I'll use that instead of the version from the local repo").

Ruby test with jenkins/maven/testLink

I am using Jenkins, maven and testLink plug-in to do automation test.
I would like to execute ruby test with Jenkins and hook theim in testLink.
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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
...
...
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codeartisans</groupId>
<artifactId>ruby-maven-plugin</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codeartisans</groupId>
<artifactId>ruby-maven-plugin</artifactId>
<version>0.1</version>
<executions>
<execution>
<id>exec-test</id>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<script>src/main/ruby/exec.rb</script>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Here is my configuration in jenkins :
test Execution --> Single build steps --> Invoke top-level maven targets :
-->goals : -X
clean
org.codeartisans:ruby-maven-plugin:0.1:exec
test
-DsuiteXmlFiles=suite.xml
and here the console output :
These will use the artifact files already in the core ClassRealm instead, to allow them to be included in PluginDescriptor.getArtifacts().
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] One or more required plugin parameters are invalid/missing for 'ruby:exec'
[0] Inside the definition for plugin 'ruby-maven-plugin' specify the following:
<configuration>
...
<script>VALUE</script>
</configuration>.
Could someone help me plz? I am new in maven, IC etc...

How to reference a maven property within another property?

Assume I get a properties file from somewhere, that has this define:
dog=POODLE
And when running maven, I pass a parameter with the property name to look up:
mvn clean install -animal=dog
I need to be able to retrieve in the pom.xml the value "POODLE" without knowing what's the property to look up for (I don't know yet that I'm looking up for a "dog", but only that I'm looking up for an "animal").
Can this be done?
I can reference in the pom ${animal} which will be replaced with dog, but then I need to look that up.
I was innocent enough to try the following, but it won't work:
${${animal}}
Thanks!
It should work if you use -Danimal=${dog}. Here is my example
<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>nested-property</groupId>
<artifactId>nested-property</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<dog>POODLE</dog>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.soebes.maven.plugins</groupId>
<artifactId>maven-echo-plugin</artifactId>
<version>0.1</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>echo</goal>
</goals>
</execution>
</executions>
<configuration>
<echos>
<echo>Animal: ${animal}</echo>
</echos>
</configuration>
</plugin>
</plugins>
</build>
</project>
run with: mvn -Danimal=${dog} install
results in
[INFO] --- maven-echo-plugin:0.1:echo (default) # nested-property ---
[INFO] Animal: POODLE
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Resources