Invalid POM due to an unresolved Maven property
Maven uses the pom.xml
configuration file to manage the project build. When parsing the file,
the tool resolves project dependencies and determines what libraries and tools are required to build the artifacts.
In the process, Maven also parses external POM files to determine transitive dependencies.
Unresolved Maven property
It may happen that a remote library POM file will contain errors, logical more so than syntactical ones. One of the reasons for these types of issues is the use of expressions referring to non-existent maven properties. In case of errors during dependency processing, Maven will skip loading transitive artifacts, and we will output an example warning:
You will quickly notice that the dependencies declared in the pom.xml
library are basically ignored and unresolvable in the project.
To find out more about the cause, add the -X
parameter. It is a shorter abbreviation form of the --debug
parameter.
[ERROR] 'dependencyManagement.dependencies.dependency.systemPath' for com.sun:tools:jar must specify an absolute path but is ${tools.jar} @
In this particular case, Maven is unable to evaluate the ${tools.jar}
expression.
Looking at the pom.xml
files, we conclude that this expression is needed to define the system tools
dependency in one of the parent POMs:
<!--...-->
<profiles>
<!--...-->
<profile>
<id>default-tools.jar</id>
<activation>
<file>
<exists>${java.home}/../lib/tools.jar</exists>
</file>
</activation>
<properties>
<tools.jar>${java.home}/../lib/tools.jar</tools.jar>
</properties>
</profile>
<profile>
<id>default-tools.jar-mac</id>
<activation>
<file>
<exists>${java.home}/../Classes/classes.jar</exists>
</file>
</activation>
<properties>
<tools.jar>${java.home}/../Classes/classes.jar</tools.jar>
</properties>
</profile>
</profiles>
<!--...-->
<dependencyManagement>
<dependencies>
<!-- JDK dependencies -->
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${tools.jar}</systemPath>
</dependency>
</dependencies>
<!--...-->
</dependencyManagement>
<!--...-->
After further verification of the dependencies of this particular artifact, you may even come to the conclusion that the system dependency is not used in this submodule.
Unfortunately, the lack of a file in the location ${java.home}/../lib/tools.jar
or ${java.home}/../Classes/classes.jar
makes the variable ${tools.jar}
uninitialized.
Specific to this example, the problem is related to JDK 11+ version. In this version, the mentioned tools have been removed.
This change is supported starting from the jaxws-rt:2.3.x
, which also entails a specification upgrade relevant to this library.
Overall, the problem is more general and can be extrapolated to a situation where Maven is unable to evaluate an expression when resolving external dependencies. Do we have any influence over this?
POM file expression evaluation
The properties source evaluation order is implemented in the org.apache.maven.model.interpolation.AbstractStringBasedModelInterpolator
for Maven v3/4 and
can be simplified as follows:
- Java Properties –
-Dkey=value
; - Maven properties –
<properties><key>value</key></properties>
; - Environment variables –
set/export key=value
.
In a multi-module project, Maven properties can be inherited by the submodules within the same project. However, these variables are not automatically propagated to the external dependencies of the project. On the other hand, Java and environment variables are initialized at the beginning of Maven processing, so adding them during the execution does not affect the evaluation. Furthermore, in the case of external dependencies, Java variables are consolidated to the level of environment variables (MNG-7563).
Knowing the above rules, you can initialize a Maven property in the external pom.xml
in several different ways, e.g., through:
- Environment variable (beware of problems with exporting dot-containing variables on Unix-like systems);
- Java Property initialized using command line
mvn -Dkey=value validate
; - Environment variable at the start of the command
key=value mvn validate
; - Maven configuration file relative to the project
.mvn/maven.config
that sets the Java Property-Dkey=value
; - Global run commands defined in e.g.,
~/.mavenrc
that set the environment variableset/export key=value
(beware of problems in IntelliJ, e.g., IDEA-19759).
The last resort is certainly to download manually (or indirectly) the dependency and add it to the compile/build paths of the artifact.
As an alternative build tool, Gradle v4-8 fares a bit better here. It doesn't throw an error for non-affected dependencies, and the artifacts get imported correctly.