exec-maven-plugin not evaluating <classpath> dependencies properly - maven

Context: I have a Maven goal that calls an executable (it happens to be a Groovy script, but it doesn't matter) which needs as an argument the path to a runtime ibrary (it happens to be a JDBC driver, but it doesn't matter either).
Instead of hardcoding the path to the driver, I'm constructing it as a classpath dependency, so that it's picked from whererever the Maven repository will happen to be (we have different environments with different OSes).
<classpath>
<dependency>postgresql:postgresql</dependency> <!-- groupId:artifactId -->
</classpath>
Problem: the classpath is not resolved as expected, instead of the path to the library, it is empty (and therefore the invocation fails).
The relevant parts of the pom.xml are below:
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version>
<scope>provided</scope>
</dependency>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>initialize-rule-plugin</id>
<phase>compile</phase>
<goals><goal>exec</goal></goals>
<configuration>
<executable>full\path\to\groovy</executable>
<arguments>
<argument>-cp</argument>
<classpath>
<dependency>postgresql:postgresql</dependency>
</classpath>
<argument>myscript.groovy</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
The debug output is:
[DEBUG] Configuring mojo 'org.codehaus.mojo:exec-maven-plugin:1.2.1:exec' with basic configurator -->
[DEBUG] (s) dependency = postgresql:postgresql
[DEBUG] (f) arguments = [-cp, Classpath { postgresql:postgresql}, ]
[...]
[DEBUG] Collected project artifacts [org.springframework:spring-context:jar:3.1.2.RELEASE:compile, org.springframework:spring-aop:jar:3.1.2.RELEASE:compile, org.springframework:spring-beans:jar:3.1.2.RELEASE:compile, org.springframework:spring-core:jar:3.1.2.RELEASE:compile, org.springframework:spring-expression:jar:3.1.2.RELEASE:compile, org.springframework:spring-asm:jar:3.1.2.RELEASE:compile, org.springframework:spring-webmvc:jar:3.1.2.RELEASE:compile, org.springframework:spring-context-support:jar:3.1.2.RELEASE:compile, org.springframework:spring-web:jar:3.1.2.RELEASE:compile, org.springframework:spring-tx:jar:3.1.2.RELEASE:compile, aopalliance:aopalliance:jar:1.0:compile, org.springframework:spring-orm:jar:3.1.2.RELEASE:compile, org.springframework:spring-jdbc:jar:3.1.2.RELEASE:compile, org.slf4j:slf4j-api:jar:1.7.1:compile, org.slf4j:jcl-over-slf4j:jar:1.7.1:runtime, org.slf4j:slf4j-log4j12:jar:1.7.1:runtime, log4j:log4j:jar:1.2.17:compile, javax.validation:validation-api:jar:1.0.0.GA:compile, org.hibernate:hibernate-validator:jar:4.3.0.Final:compile, org.jboss.logging:jboss-logging:jar:3.1.0.CR2:compile, org.hibernate:hibernate-entitymanager:jar:4.1.7.Final:compile, org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:jar:1.0.0.Final:compile, dom4j:dom4j:jar:1.6.1:compile, org.javassist:javassist:jar:3.15.0-GA:compile, org.hibernate:hibernate-core:jar:4.1.7.Final:compile, antlr:antlr:jar:2.7.7:compile, org.hibernate.common:hibernate-commons-annotations:jar:4.0.1.Final:compile, org.hibernate.javax.persistence:hibernate-jpa-2.0-api:jar:1.0.1.Final:compile, org.codehaus.jackson:jackson-mapper-asl:jar:1.9.10:compile, org.codehaus.jackson:jackson-core-asl:jar:1.9.10:compile, javax.servlet:jstl:jar:1.2:compile, commons-dbcp:commons-dbcp:jar:1.4:compile, commons-pool:commons-pool:jar:1.5.4:compile, org.codehaus.groovy:groovy-all:jar:2.0.5:compile]
[DEBUG] Collected project classpath [C:\projects\myproject\target\classes]
[DEBUG] Toolchains are ignored, 'executable' parameter is set to c:\full\path\to\groovy
[DEBUG] Executing command line: cmd /c c:\full\path\to\groovy.bat -cp C:\projects\myproject\target\classes myscript.groovy
As it can be seen, it does not pick up the classpath to the driver (which exists).
I have tried with and without also including the dependency's version number in the reference.
Thank you in advance.

As per my comment, I found a different way to do the same thing. Since there was no other solution posted, I'll post it as an answer if anyone runs into the same problem.
The key is to use a different plugin, which creates, on-the-fly, properties populated with the path to a jar.
<plugin>
<groupId>org.bitstrings.maven.plugins</groupId>
<artifactId>dependencypath-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>set-all</id>
<goals>
<goal>set</goal>
</goals>
<configuration>
<propertySets>
<propertySet>
<includes>
<include>postgresql:postgresql:jar</include>
</includes>
</propertySet>
</propertySets>
</configuration>
</execution>
</executions>
</plugin>
[...]
<execution>
<id>my-script</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>path/to/groovy</executable>
<arguments>
<argument>-cp</argument>
<argument>${postgresql:postgresql:jar}</argument>
<argument>my-script.groovy</argument>
</arguments>
</configuration>
</execution>

Related

IOException thrown when processing xsd dependencies in maven

I have a problem while processing .xsd file during my maven build.
I use jaxb2 plugin but I have to download external dependiencies from my .xsd files. The problem is that these dependencies (.xsd) are from enviroment which is unstable and very often my build fails because maven cannot download xsd file. How to configure jaxb plugin to force him to try download xsd few times to prevent build failure?
Part of my pom.xml configuration:
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<configuration>
<strict>false</strict>
<extension>true</extension>
<args>
<arg>-Xfluent-api</arg>
<arg>-XtoString</arg>
<arg>-Xsetters</arg>
<arg>-XenumValue</arg>
</args>
<plugins>
<plugin>
<groupId>net.java.dev.jaxb2-commons</groupId>
<artifactId>jaxb-fluent-api</artifactId>
<version>${jaxb.fluentapi.version}</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.9.3</version>
</plugin>
</plugins>
<bindingDirectory>src/main/resources/jaxb</bindingDirectory>
<bindingIncludes>
<include>bindings.xml</include>
</bindingIncludes>
<schemas>
<schema>
<fileset>
<!-- Defaults to schemaDirectory. -->
<directory>${project.basedir}/src/main/resources/orbeons</directory>
<!-- Defaults to schemaIncludes. -->
<includes>
<include>*.xsd</include>
</includes>
</fileset>
</schema>
</schemas>
</configuration>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/generated-sources/orbeons</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Author of the maven-jaxb2-plugin here.
You have two parts here: managing the downloads of external resources and compiling the schemas, rewriting "external" links to local files.
The first (managing downloads) is not in the scope of the maven-jaxb2-plugin, the second is supported with
catalogs.
In short, you can create a catalog file like this:
REWRITE_SYSTEM "http://www.w3.org" "w3c"
Or this:
REWRITE_SYSTEM "http://schemas.opengis.net" "maven:org.jvnet.ogc:ogc-schemas:jar::!/ogc"
And use this file to "rewrite" absolute links to local files or resources within Maven artifacts:
<configuration>
<catalog>src/main/resources/catalog.cat</catalog>
</configuration>
As for the first part, I don't think managing downloads with retries, continuations and all other stuff should be in the scope of the JAXB2 Maven plugin.
ps. You don't need build-helper-maven-plugin/add-source with maven-jaxb2-plugin, source directory is added automatically.
Apparently the maven-jaxb2-plugin does not support such a feature. (And neither does the maven-download-plugin nor even the maven-dependency-plugin).
Three solutions come into my mind at the moment (plus two and a half inspired by LIttle Ancient Forest Kami's comment) [Numbers reflect the precedence of what I would do]:
Use a CI tool (Jenkins, etc.) that supports retry on job failure. [1]
Handmade:
Use the GMavenPlus plugin with a script ... [2]
Use the Maven AntRun plugin with a script ... [3]
Use the Exec Maven plugin with a program ... [5]
... that performs the download and retry and bind it to the generate-resources phase in your project's POM.
Create a Maven plugin with appropriate parameters (url, outputDirectory, retryCount) that uses the maven-download-plugin and performs the retry. Bind its goal to the generate-resources phase in your project's POM. [4]
Create a check-download Maven project that uses the maven-download-plugin bound to the generate-resources phase to download the .xsd. [6]
Create a shell script that contains the following (in pseudo code):
download:
counter++
<check-download project>/mvn generate-resources
if error and counter < maxRetryCount goto download
if not error
<your project>/mvn ...
else
display appropriate error message
There is also a question Maven download retry? from 2005. Unanswered.

Wrapping Ant in Maven - JAVA_HOME points to the JRE but works with just Ant

I have an Ant project that builds just fine on its own. I'm now trying to wrap it in a Maven build that will kick off the Ant build using maven-antrun-plugin. When I do this the build fails and I get this error,
[ERROR] C:\Users\bobby\workspace\libraries\build-targets\common-targets.xml:170: Unable to find a javac compiler;
[ERROR] com.sun.tools.javac.Main is not on the classpath.
[ERROR] Perhaps JAVA_HOME does not point to the JDK.
[ERROR] It is currently set to "C:\Java\jdk1.8.0_65\jre"
There are a lot of SOF posts on this error but I feel like mine is unique since it only happens when I'm wrapping the Ant build in Maven i.e., I do not get this error on the same project when I just say $ ant build.
This is part of my pom.xml file
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<tasks>
<ant antfile="build.xml" target="build" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>add-jar</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>build/bin/myWarFile.war</file>
<type>war</type>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
My JAVA_HOME Environment Variable is set to C:\Java\jdk1.8.0_65.
The file that is mentioned in the error is from a library my work maintains where we keep all of our Jars. In that file here is what's on line 170
<target name="compile-src">
<!-- Compile source -->
<javac srcdir="${java.src.dir}"
destdir="${class.dir}"
debug="${debug.flag}"
deprecation="${deprecation.flag}"
nowarn="${warnings.flag}"
optimize="off"
source="${source.value}">
<classpath refid="compile.classpath"/>
</javac>
</target>
The line with source= is line 170.
It's a common issue. Try with this configuration:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
...
<!-- Add this dependency to your ant-run configuration -->
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.5.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
...
</plugin>
Maven uses Java's system property java.home, which is not the same as the environment variable JAVA_HOME, but it is using it to compute its java.home by tacking on the jre sub-directory, as witnessed. Consequently, stuff needed by Ant is simply not available in the jre directory.
However, this configuration ensures that Ant's plugin dependencies are correctly satisfied.
You need to point to JDK not JRE. Just remove ire and try.
It is currently set to "C:\Java\jdk1.8.0_65\jre"
And if your JDK is set - another workaround - Can you copy tools.jar from jdk lib to jre lib and see if it works.

How to set classpath for mvn exec:exec?

I'm trying to have mvn exec:exec (or mvn exec:java) run my program with a local jar in the classpath. However the jar fails to load:
Exception in thread "main" java.lang.Error: Unable to load voice directory. java.lang.ClassNotFoundException: com.sun.speech.freetts.en.us.cmu_us_slt_arctic.ArcticVoiceDirectory
at com.sun.speech.freetts.VoiceManager.getVoiceDirectories(VoiceManager.java:211)
at com.sun.speech.freetts.VoiceManager.getVoices(VoiceManager.java:111)
at com.sun.speech.freetts.VoiceManager.getVoice(VoiceManager.java:521)
at xpress.audio.TTS.<init>(TTS.java:66)
at xpress.audio.TTS.<init>(TTS.java:62)
at xpress.audio.AudioProducer.main(AudioProducer.java:18)
Running the program directly from the CLI using java works:
C:\XpressAudio\target\classes>java -cp "C:\XpressAudio\target\XpressAudio-1.0-SN
APSHOT-jar-with-dependencies.jar;C:\XpressAudio\cmu_us_slt_arctic.jar;C:\XpressA
udio\en_us.jar;C:\XpressAudio\*" xpress.audio.AudioProducer
Here's the <build> part of my pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<mainClass>xpress.audio.AudioProducer</mainClass>
</configuration>
<dependencies>
<dependency>
<groupId>cmu_us</groupId>
<artifactId>slt_arctic</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/cmu_us_slt_arctic.jar</systemPath>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
Could someone tell me how should I edit the pom.xml such that mvn exec:exec works like the java command above?
com.sun.speech.freetts.en.us.cmu_us_slt_arctic.ArcticVoiceDirectory is a class in cmu_us_slt_arctic.jar
In maven it is possible to include a local jar (which is outside of maven repository) using systemPath. But since the scope is system (for dependencies declared with systemPath), there are few limitations and because of that it only works with exec:java.
For exec:exec, the above solution will not work because maven does not include system scoped dependencies in its generated (runtime) classpath (%classpath) so the solution is to use your own classpath instead of maven generated classpath as shown below.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<argument>local.jar;target/project-jar-with-dependencies.jar</argument>
<argument>xpress.audio.AudioProducer</argument>
</arguments>
</configuration>
</plugin>
Replace local.jar with all the jar files that are required to be present at some fixed location (here project root is assumed, where pox.xml is located). Also note the use of 'project-jar-with-dependencies.jar', in your case it should be target\XpressAudio-1.0-SN
APSHOT-jar-with-dependencies.jar.
standard java does not allow us to specify multiple -cp arguments, but exec-maven-plugin does, so
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution><goals><goal>exec</goal></goals></execution>
</executions>
<configuration>
<executable>./java.pl</executable>
<arguments>
<argument>-ea</argument>
<argument>-cp</argument><argument>.</argument>
<argument>-cp</argument><argument>my.jar</argument>
<argument>-cp</argument><classpath/>
<argument>org.example.ConfigByXml</argument>
</arguments>
</configuration>
</plugin>
note the call to java.pl above, this is the trick
#!/usr/bin/env perl
while (#ARGV) {
$arg = shift;
if ($arg eq '-cp' or $arg eq '-classpath') {
push #cp, shift;
next;
}
push #args, $arg;
}
unshift #args, 'java', '-cp', join(':', #cp);
# print 'args: ', join(' --- ', #args); # uncomment to debug
exec #args;
understand what java.pl does and use it or do the equivalent in bash, cmd, powershell, whatever..
To set additional classpath in maven you should use in your maven configuration file as below:
<additionalClasspathElements>
<additionalClasspathElement>path/to/additional/jar</additionalClasspathElement>
</additionalClasspathElements>
For more detail:
http://maven.apache.org/surefire/maven-surefire-plugin/examples/configuring-classpath.html

Specify javaagent argument with Maven exec plugin

I have a similar question to: this previous question
I am converting a Java project using Netbeans to Maven. In order to launch the program, one of the command-line arguments we need is the -javaagent setting. e.g.
-javaagent:lib/eclipselink.jar
I'm trying to get Netbeans to launch the application for development use (we will write custom launch scripts for final deployment)
Since I'm using Maven to manage the Eclipselink dependencies, I may not know the exact filename of the Eclipselink jar file. It may be something like eclipselink-2.1.1.jar based on the version I have configured in the pom.xml file.
How do I configure the exec-maven-plugin to pass the exact eclipselink filename to the command line argument?
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Xmx1000m</argument>
<argument>-javaagent:lib/eclipselink.jar</argument> <==== HELP?
<argument>-classpath</argument>
<classpath/>
<argument>my.App</argument>
</arguments>
</configuration>
</plugin>
I figured out a way that seems to work well.
First, setup the maven-dependency-plugin to always run the "properties" goal.
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<id>getClasspathFilenames</id>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
Later on, use the property it sets as documented here with the form:
groupId:artifactId:type:[classifier]
e.g.
<argument>-javaagent:${mygroup:eclipselink:jar}</argument>
Simply define a property for the eclipse link version and use the property in your <dependency> and the exec plugin:
<properties>
<eclipselink.version>2.4.0</eclipselink.version>
</properties>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>${eclipselink.version}</version>
</dependency>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Xmx1000m</argument>
<argument>-javaagent:lib/eclipselink-${eclipselink.version}.jar</argument>
<argument>-classpath</argument>
<classpath/>
<argument>my.App</argument>
</arguments>
</configuration>
</plugin>
the maven-dependency-plugin and exec-maven-plugin should be put under the node ,otherwise it will not work

XML maven artifact not on classpath

I have some external configuration (XML files) that are installed in Maven. I need to have them on my test classpath but they aren't appearing.
They must stay as XML, I cannot package them inside a Jar - but I am willing to try anything else for this, custom plugin etc.
(Please don't inform me that Maven is only for Jars - that's simply not true (and if you provide a reference refuting that I can assure you it's out-of-date/misinformation).
The dependencies are specified thus:
<dependency>
<groupId>some.group</groupId>
<artifactId>some.artifact</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>xml</type>
<classifier>some.classifier</classifier>
</dependency>
These XML artifacts have been created by the build-helper plugin (so there's no 1-2-1 with their project's POM).
My only current hacky solution is to, check for the M2_HOME property and load the files from there (as they're defined as dependencies Maven does pull them down) - but I'm not happy with this.
EDIT: The next best hack is probably to use the maven-dependency-plugin to copy these to the output directory (target/classes). If my config is fine for Jars then this smells like a Maven bug.
EDIT 2: #khmarbaise asked for the build-helper-plugin config:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>target/classes/ddl-seed.xml</file>
<type>xml</type>
<classifier>ddl-seed</classifier>
</artifact>
<!-- ... more definitions -->
This generates the correct maven-metadata-local.xml data for all the XML artifacts.
Unfortunately I can find no way of forcing maven to add the test dependency specified to the test classpath, other than this stinky hack of copying it to a directory on the test classpath.
This seems the quickest way (it's for a test dependency), avoiding any JAR creation.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.acme.gid</groupId>
<artifactId>com.acme.aid</artifactId>
<version>${project.version}</version>
<classifier>ddl</classifier>
<type>xml</type>
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>

Resources