1

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.

Community
  • 1
  • 1
  • Please show your pom file... – khmarbaise Jan 30 '17 at 22:27
  • Maven itself ignores MANIFEST.MF so I don't really understand what is your problem with the classpath? This is being created by the resulting application... – khmarbaise Jan 30 '17 at 23:40
  • 1
    As far as I know the Class-Path entries of the manifest.mf are not used for compilation. – J Fabian Meier Jan 31 '17 at 08:24
  • @JFMeier Yeah, that's what I thought too. Please see this: http://stackoverflow.com/questions/1344202/bad-path-warning-where-is-it-coming-from – Robert Poole Jan 31 '17 at 16:58
  • See also [this jax-ws Jira ticket](https://java.net/jira/browse/JAX_WS-653). This issue was supposedly fixed, but people keep running into it when using older JARs from places like Maven Central. – Robert Poole Jan 31 '17 at 17:24
  • @RobertPoole The classpath entries in MANIFEST.MF are simply ignored during the build of jar's with Maven (except you are running Tycho inside Maven which means OSGi). Running them using the command line etc. is different story...Apart from that the listed references are related to IDE usage...which is something different...BTW: Do you have a working example which shows the problem? Maybe in a Github repo? – khmarbaise Jan 31 '17 at 17:55
  • @RobertPoole Are you running an OSGi build? Or are you inside your IDE ? Because the [jar](http://search.maven.org/#artifactdetails%7Ccom.sun.xml.bind%7Cjaxb-core%7C2.2.11%7Cjar) you have in your error message contains OSGi bundle informations...and yes a classpath entry which is ignored by Maven but might not be ignored by your IDE... – khmarbaise Jan 31 '17 at 18:11
  • @khmarbaise I just realized my previous response to you wasn't entirely accurate. Maven itself doesn't care about the Class-Path embedded inside the jar's MANIFEST.MF, but javac certainly does, and Maven does call javac to do the compiles. – Robert Poole Jan 31 '17 at 21:01
  • @khmarbaise Also, everything you have posted since your initial comments tells me you never bothered reading any of the articles at the links I added to my question. Everything you've said so far seems to be completely off the mark, so I have to say you're being entirely unhelpful now. For example, I can confirm that the build fails from both the IDE and the command line -- in the exact same way. So the theory that this is an IDE-specific build problem does not hold. – Robert Poole Jan 31 '17 at 21:12
  • @khmarbaise Also, we're not using Tycho or OSGI, so I'm not sure how you got all that from a single error message. Tycho is for building Eclipse plugins, which we are not doing. And again, classpath entries in JARs are honored by javac, which is called by Maven, so yes, classpath entries *do* matter. At this point, I've pretty much solved this problem so you don't need to keep speculating. I'll be posting an answer shortly. – Robert Poole Jan 31 '17 at 21:20
  • Sorry I was unable to provide toy examples on Github. Even posting our POM files would be problematic, because they're huge, there are numerous subprojects, and I'd have to redact any information pertaining to our customer. Besides, the links I provided do, in fact, provide some limited examples. – Robert Poole Jan 31 '17 at 21:25
  • @RobertPoole I really find this interesting because we never had such problems although we use a lot of Class-Path entries with non-existent jars (we use Maven 3.3.3 and 3.3.9). I tried to find out what triggers this problem and if it ever was discussed by the Maven people, but I couldn't find anything useful. – J Fabian Meier Feb 01 '17 at 07:59
  • I'm asking in detail cause I'm also on a numerous projects which very large number of modules (OSGi, non OSGi builds) ca. 700 modules etc. and never had such an issue also having several jar's which contains non existing jars...Which JDK do you use? I only saw this issue in relationship with IDE's which handles compiling etc. their own...but that was longer ago... – khmarbaise Feb 01 '17 at 10:00

2 Answers2

1

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.

0

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>
khmarbaise
  • 92,914
  • 28
  • 189
  • 235
  • The post I'm referencing may be 7 years old, but it is the _only_ working advice I have found. The _only_ working advice. – Robert Poole Feb 14 '17 at 16:59
  • Furthermore, if you want to provide a relevant link to the current docs for the maven compiler plugin, here's a more direct link that actually contains a relevant example involving `-Xlint`: http://maven.apache.org/plugins/maven-compiler-plugin/examples/pass-compiler-arguments.html However, please note that we are forced to use version 2.5.1 of the compiler plugin (the latest appears to be 3.6.1). Why? Because this is being developed for a third party, and that's what they specified. So guess what? The syntax you specify here won't work for me at all. – Robert Poole Feb 14 '17 at 17:06
  • Finally, I should point out that the example cited at the aforementioned link (my previous comment) clearly shows an even better way to specify `-Xlint` arguments for the use case where you need to turn on all checks/warnings except for one or two, and it allows you to do it all on one line: `-Xlint:all,-options,-path` The use of a comma separated list of warnings looked a little weird to my eyes, but javac supports this exact syntax from the command line. Too bad this doesn't work for command line parameters like `-bootclasspath`; see http://stackoverflow.com/a/42042367/7491719 – Robert Poole Feb 14 '17 at 17:35