How to enable tools.jar in uberjar (using maven-shade-plugin)?
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>test</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.7</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>test.Test</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
mvn install
succeeds (i.e. maven sees the dependency tools.jar
at build time), but on execution I have
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/javac/api/JavacScope
at test.Test.main(Test.java:24)
Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.api.JavacScope
...
source to share
The maven-shade plugin assumes system dependencies and does not actually include them in a fat jar
A quick dirty workaround is to install tools.jar in your maven repository and reference it as a compile-dependent dependency
The best workaround is to use maven-assembly-plugin and include tools.jar as<file>
source to share
Most of the dependencies are <scope>system</scope>
not available for plugins.
Also, including the tools.jar in your uberjar doesn't carry over badly in newer JVM versions. This is fine if you have a super controlled and limited deployment environment, but it is usually best to discover tools.jar and use it.
Here's an example from the maven-javadoc-plugin (it looks at tools.jar and then checks that the active classloader has classes from tools.jar)
In your case, instead of searching, com.sun.tools.doclets.Taglet
you can search com.sun.tools.javac.api.JavacScope
to check for a valid environment.
From there it would be trivial to create a new ClassLoader with your uberjar + tools.jar and then execute what you need from the valid scope Thread.currentThread().setContextClassLoader()
source to share