Maven build failure involving MANIFEST.MF classpath in dependency JARs - java

First off, I'm a long time user (and beneficiary) of StackOverflow, but this is my first question. I've done plenty of searching on this topic, but most of the articles I've turned up talk about generating JAR files, not working with 3rd party JARs from the Maven Central repo which I don't really have the power to fix. The few solutions I've seen floating around aren't really acceptable.
The problem is that most of the jaxb JARs found in the Maven Central repository contain classpath entries (in the MANIFEST.MF file) that point to dependencies, and those dependencies are specified with relative paths -- typically assuming that dependency bar.jar exists in the same directory as foo.jar.
This is fine if you have all your JAR dependencies in a single lib directory, for example. But:
Maven wants to maintain its own local repository, so every single packaged JAR lives in its own directory (with each version in a separate subdirectory).
Maven JARs are typically named with the version info embedded in the filename, whereas the classpath entry in MANIFEST.MF specifies the dependency with just the base filename (no version).
The net result is an error message like this:
[ERROR] bad path element
"C:\Users\rpoole\.m2\repository\com\sun\xml\bind\jaxb-impl\2.2.11\jaxb-core.jar":
no such file or directory
One solution is to write a script or small app to go through all the JARs and strip out the classpath info from the embedded MANIFEST.MF file. But that is not very clean, and requires an extra step before doing the actual build.
Another potential solution is that some newer published versions of the JARs in question have supposedly fixed this classpath problem, so therefore use the latest and greatest. Unfortunately, this app I'm working on is legacy, and is being developed for a 3rd party, so I can't update the dependencies beyond a certain version. So far, all the jaxb JARs that I have poked into seem to have issues.
Is there a way to tell Maven to ignore the embedded classpath in the JAR and only rely on Maven's own dependency resolution? I've tried things like reordering dependencies, but that doesn't work (or moves the build problem from one subproject to another).
One additional annoyance: There is a "blessed" Maven repo we have that seems to let the build complete with no problem, but so far I've been unable to figure out why this particular set of JARs builds OK. I suspect someone may have gone in and tweaked some JARs or POMs manually, but there's scant information, and diff tools aren't really helping much.
Regardless, the project should build from scratch.
What would be nice is if I could specify something like an exclusion block in the pom.xml for the subproject that's breaking, but for dealing with a JAR's embedded classpath instead of Maven's own transitive dependencies (specified by groupId/artifactId).
Edit: Apparently, some people believe that this is impossible, and that Maven ignores the Class-Path entry in Manifest.MF. However, this is a known issue, as discussed in this StackOverflow article. There's also another good article which explains some of the history of this a bit better.
The problem is that I can't go through the JARs and edit the MANIFEST.MF files on each as part of the build process. That's just not a practical approach, even if automated by script. I need a solution that actually will work for code that is already in production. These issues were supposedly fixed in later versions of the JARs in question, but I may not be able to use newer versions of those.
Additionally, one of the proposed fixes is to add -Xlint:-path to the compiler args, which suppresses the error message. However, the build simply fails at another point for me, so at first blush this does not appear to be a good solution either. I'll be trying this again because according to this, the syntax for compiler arguments inside POM files is a bit wonky.

I hate answering my own question, but I finally did manage to get past this problem. For those who keep insisting that Maven builds can't possibly be affected by the Class-Path entry in a jar's MANIFEST.MF, please read this article by Michael Bayne. It summarizes the problem and the solution rather nicely. Hint: javac certainly does care about the embedded classpath in jars.
The trick is to add -Xlint:-path to the compiler arguments, although I was dubious of this solution initially. Doing this will suppress the bad path element warnings/errors, and therefore Maven won't prematurely halt the build. The problem I had was figuring out the correct syntax for embedding these arguments in the pom.xml. That's where this article comes in handy. Therefore, the compiler plugin's configuration has to look like this to be understood properly:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<compilerArguments>
<Xlint/>
<Xlint:-path/>
</compilerArguments>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
Note that this syntax is not very good XML (as Bayne points out), and most IDEs will flag the second Xlint line as an error, but it will work with Maven. Using the syntax given in some Maven tutorials may result in the arguments not being passed to the compiler at all, or only the last argument being passed.
Once this problem is taken care of, you may discover other build problems (I certainly did), but at least those problems won't be hidden from you any longer.

The problem is that you are referencing a post which is seven years old..and don't use more recent versions of the maven-compiler-plugin:
The arguments to the javac compiler can better done like this:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<compilerArgs>
<arg>-Xlint</arg>
<arg>-Xlint:-path</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>

Related

Configure maven plugin version without changing pom.xml manually

Problem Description
I'm working with a collection of old projects from defects4j. My problem now is that since I want to combine those projects with a newer maven plugin, a regression test tool, there are some issue with the maven surefire plugin version.
In the pom.xml that come along with the projects, there are no specifications of surefire version:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>plain</id>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<runOrder>random</runOrder>
</configuration>
</execution>
</executions>
</plugin>
However, the regression tool (made into a maven plugin), require surefire version of 2.14 and above. So I get error like this:
[ERROR] Failed to execute goal edu.illinois:starts-maven-plugin:1.4-SNAPSHOT:select (default-cli) on project commons-lang: Unsupported Surefire version: 2.12.4. Use version 2.13 and above
Efforts Done
I checked several stackoverflow posts, and they talked about the effective pom. When I run mvn help:effective-pom, I can see that the version of surefire used is
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
Question
Since the project collection in defects4j does not specify surefire version in their pom.xml, is there a way to specify the surefire version used to 2.14 or above from command line? I want to prevent from manually editing the pom every time.
Update
by running mvn dependency:resolve-plugins, i get
Plugin Resolved: maven-surefire-plugin-2.12.4.jar
So it seems to me that somehow maven use 2.12.4 as a default. The reason maybe that I used this version previously. How do I fix this?
Without modifying the pom manually?
Any advice will be welcomed!
Update:
Problem solved by editing maven's super pom.
Maven takes the newest version from the repository if there was no version fixed in your POM, parent POM or the super POM (from which every Maven project inherits).
It is best practise to fix a version "manually" in the POM. The best place for this is a parent POM from which the projects inherit (this means, only one place to change).
You cannot just supply a version from command line. Unless you do some tricks like putting <version>${surefire.version}</version> into the plugin definition and set this property from command line.
I'm 4+ years removed from working with poms so don't remember everything, but consider a couple of things.
First, since the pom you show isn't specifying the version of surefire to use I don't think that the 2.12.4 version can be coming from that directly. Try getting a dependency tree to see where things are coming from. Try How can you display the Maven dependency tree for the *plugins* in your project? for that and a few other suggestions.
Second, I think I recall that in your own pom you should be able to specify the version of plugin to associate with a dependency that doesn't specify one. You'll have to research that option yourself.
I think your best bet is the dependency tree to find what's using what and where things are coming from. If you get the tree and still can't figure out what to do try adding the tree output to your question. (You can edit out parts that are proprietary, or clearly unrelated.)

Precedence packagingExcludes and packagingIncludes maven war plugin

Recently I configured my application to use "skinny wars" that was described on codehaus (title: Solving the skinny war problem). Basically I exclude all jars from the war and add it as a war and pom dependency to the ear. Now I ran into a problem with two jars. So to me the logical thing to do was include them in the war file using packagingInclude.
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
<packagingIncludes>WEB-INF/lib/A.jar, WEB-INF/lib/B.jar</packagingIncludes>
</configuration>
</plugin>
Using a regex as showed in de plugin documentation and this answer but it didn't seem to do anything. It just excludes everyting.
In the source code of the plugin I found that it uses the DocumentScanner of org.codehaus.plexus ยป plexus-utils. I didn't quite understand how it works.
I thought this was a no brainer. But what am I doing wrong? Could it be that the inclusion doesn't work when A is also a transitive dependency of C?
Edit: Does plugin version play any role? Now I am using 2.6 but previously version 2.1-alpha-2 was used.
Found this answer as well. The following line (and only this line) works:
<packagingExcludes>%regex[WEB-INF/lib/(?!common-A|common-B).*.jar]</packagingExcludes>
Only common-A-x.x.jar and common-B-x.x.jar are in the WEB-INF/libfolder of the war file. It should be possible to extract the common part in the regex but what I tried didn't work.
try to use the includes only without the wildcard excludes definition. Since you exclude all jars this eats up your includes. As far as I understand the doc (and from my memories), the default is to include everything but as soon as you specify an include the plugin will only include your list of jars.

Maven Plugin for project semantic versioning

I'm looking for a maven plugin that will help me manage version names and codes of every build that is made on our CI environment. Something that will be able to attach a prefix to the main version code or even update it (not changing the pom.xml). For example:
project version: 2.0.1
git/svn revision: 2342334
jar output: name-2.0.1-2342334.jar
maven repo: ../path/to/local/maven/repo/<package path>/2.0.1-2342334/
The main requirements to this plugin are:
Must be in Maven Repository (which means that NO additional setting required to add this plugin in my pom.xml and run maven)
Must not edit the pom, each time it's applied
A configuration file, would be great, so I could manage the versioning process
Must be able to edit the output file metadata (so the version will be applied as if it was written in the pom.xml file in the first place)
So far I found only maven-buildmetadata-pluging but unfortunately it's not in Maven Repo, so I'm stuck. Any help would be great.
Hosting your own maven repository is very easy, using either Nexus or Artifactory. You can also use the Artifactory cloud version (I'm not affiliated with them...) so it may solve your problem. BTW - a simple server with Apache does the trick as well, but with more work..,
Regarding the plugins: If you deploy snapshot applications then each gets its own version based on timestamp.
For releases another option is to run an svn info and put the result (or part of it) into the generated artifact. The information can then be accessed by the code.
If you change the version of your artifact the pom has to reflect the change, cause otherwise it's not reproducible.
If you change something in your build process (like added versions, whatever) it has to be reflected in the pom file. Otherwise you can not reproduce the build process with the same result.
You have written not to change the pom file but maintaining a separate file. So the questions is: Why not using the pom file itself, cause it's intended exactly for that purpose.
Furthermore all informations which you mentioned by the maven-buildmetadata-plugin can be achived by using existing maven plugins (like build-helper-maven-plugin, buildnumber-maven-plugin).
The SCM information can be used by using the buildnumber-maven-plugin which provides information like SCM revision number (SVN or GIT hash).
An on the other hand if you don't like to change your pom file manually you can use either the versions-maven-plugin or the maven-release-plugin which automatically can change informations in your pom file and handle all these things automatically.
To maintain metadata in your producted artifacts you can configure all plugins (like ear, war, jar) etc. more or less like this where the buildNumber is comming from buildnumber-maven-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<index>true</index>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<buildNumber>${buildNumber}</buildNumber>
</manifestEntries>
</archive>
</configuration>
</plugin>
And of course if you really like to use Maven you should have to use an repository manager as already mentioned like Artifactory or Nexus which make life easier.
I just would like to add (although the question is 5 years old and already has an accepted answer) that the Buildmetadata Maven Plugin was not available on the Maven Repo at first, but it is now (since late 2013). People who would like to give it a try find the artifact at the following locations :
com.redhat.rcm.maven.plugin:buildmetadata-maven-plugin
de.smartics.maven.plugin:buildmetadata-maven-plugin
Please note that the name has changed from maven-buildmetadata-plugin to buildmetadata-maven-plugin due to naming conventions.
I'm one of the "original" authors of this plugin at smartics. If you would like to use it, you probably would like to use the fork provided by Red Hat. To my knowledge the two versions do not differ very much and they have not been synced since there is just so much other stuff to do and the plugin seems to be feature stable. ;-)
The source code for both versions is also available on GitHub:
release-engineering/buildmetadata-maven-plugin
smartics/buildmetadata-maven-plugin
As already stated, you have to change the version in the pom. One way of doing that, in combination with the release plugin is:
mvn \
se.bjurr.gitchangelog:git-changelog-maven-plugin:VERSION_HERE:semantic-version \
release:prepare release:perform
Using Git Changelog Maven Plugin

Smarter Native Dependency Handling with Maven

I'm currently in the midst of converting a large multi-module project (~100 sub-modules) to use Maven. Currently we use Ant + Ivy.
So far no major issues have cropped up and I'm comfortable that Maven is still a good fit. However, I wonder if there is a better way to handle native dependencies.
So far I have come to the following conclusions.
It's best to install each native dependency into the maven repo either as a standalone library or an archived package containing multiple dependencies.
Rather than get lost in declaring each and every dependency with the Maven dependency plugin, I opted to give each a classifier (e.g. natives-win32) and use the following in the parent POM:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<includeClassifiers>natives-win32</includeClassifiers>
<outputDirectory>${project.build.directory}/natives</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
So far this seems to be a simple all-round solution that doesn't require too much messing about to add new native dependencies. It also offers me a simple all-round solution for managing natives. The only thing I must do is ensure that my /natives/ directory is defined on java.library.path.
One thing that bothers me (a little) about this approach is that all my native dependencies get copied around to each sub-module that expresses a transitive dependency on them, whilst my happy jar libraries are added to the classpath referenced to where they sit in my local repository (no copy required).
Is there no way to be smarter about this and have my natives referenced from withing their repository location (assuming I don't have them archived, i.e. dll). That would save a bunch of unnecessary copying about.
Are there any other potential gotchas' that I should be concerned about with the above approach?
Your snippet shows a goal attached to a build phase, not a dependency. Is the 'copy dependencies' goal in a super pom and inherited by all modules? There's no way to move it only to the modules which are going to be run/packaged as an app?
It could be, that I didn't got it. But why don't you deploy all your native libs into the repository at first. If the native libs are stable and change seldom, That could be done in a seperate reactor.
And afterwards you reference those native dependencies simply via GAV as any other dependency. Also the problem af unnecessary copying is solved by that.
I ended up using the maven natives plugin and dealing with the fact that I have redundant copies of the native libraries around the place. The reason for this was primarily due to the simplicity that the plugin offers and the fact that it also has a related eclipse plugin that sets up natives in developers eclipse environment without intervention.

Moving to Maven from GNUMake

I've been a long time user of the Make build system, but I have decided to begin learning the Maven build system. While I've read through most of the online docs, none seem to give me the analogies I'm looking for. I understand the system's lifecycle, but I have not see one reference to compile step dependencies. For example, I want to generate a JFlex grammar as part of the compile lifecycle step. Currently, I see no way of making that step a pre-compile phase step. Documentation seems to be limited on this. In general, the concept of step dependencies seem to be baked into Maven and require a plugin for any alteration. Is this the case? What am I missing, because currently the Maven build system seems very limited in how you can setup compilation steps.
You can do anything in Maven. It generally has a default way to do each thing, and then you can hook in and override if you want to do something special. Sometimes it takes a lot of Stack Overflowing and head scratching to figure it out.
There is even an official JFlex Maven plugin.
Whenever possible, find someone who has made a Maven plugin do what you want. Even if it isn't 100% right, it may at least give you an idea on how to make maven do something.
Minimal configuration
This configuration generates java code of a parser for all grammar files (.jflex , *.jlex , *.lex , .flex ) found in src/main/jflex/ and its sub-directories. The name and package of the generated Java source code are the ones defined in the grammar. The generated Java source code is placed in target/generated-source/jflex , in sub-directories following the Java convention on package names.
pom.xml
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<groupId>de.jflex</groupId>
<artifactId>jflex-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!-- ... -->
</build>
<!-- ... -->
</project>
This feels like the maven way to do things. Put your stuff in the right folders (src/main/flex), and this plugin will automatically build it into your project. If you want to do fancier custom stuff, there are some options. but Maven is all about favoring convention over configuration.
To be frank I think that your current mindset maps much better to ant than to maven, and I would suggest starting with that.

Categories