Shade Java Classes Using Maven

While working on projects with multiple dependencies, sometimes, you may experience conflicting dependencies. For example, consider the following scenario on two projects, where:

  • Project A depends on Project B and C.2.0.jar
  • Project B depends on C.3.0.jar

Usually, Project A downloads C.2.0.jar and Project B downloads C.3.0.jar. The two projects add the jar in the corresponding classpath. The problem may occur if C.2.0.jar and C.3.0.jar are incompatible. Project A that has dependency on Project B, requires both C.2.0 and C.3.0 jars in its class path. Due to incompatibility between the two jars, errors occur.

The error occurred only due to the Project A’s dependency on Project B, which requires C.3.0.jar. In such a case, Maven allows a project to shade certain packages/classes, that is, it changes the classpath of such packages and bundles it with the project.

Let us understand Maven shading with a real-time example.

An Hadoop-2 project depends on guava-11.0 and wants to integrate with Qubole’s auto scaling module (ASCM). ASCM depends on guava-16.0 that is incompatible with guava-11.0. Hence, running Hadoop-2 with ASCM results in conflicting jars that causes errors.

So, ASCM modifies its build process to shade jars represented by guava-16.0 and adds it into its own package (ascm-1.0.jar) with a modified namespace.

The modified POM file would be as shown in the following XML file.

<build>
  <plugins>
    <plugin>
      ...
    </plugin>
    <plugin>
      ...
    </plugin>

    <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>
            <artifactSet>
              <excludes>
                <exclude>classworlds:classworlds</exclude>
                <exclude>javax.servlet:*</exclude>
                <exclude>commons-logging:commons-logging</exclude>
                <exclude>com.fasterxml.jackson.core:*</exclude>
                <exclude>logkit:*</exclude>
                <exclude>avalon-framework:*</exclude>
                <exclude>org.apache.maven:lib:tests</exclude>
                <exclude>log4j:log4j</exclude>
              </excludes>
            </artifactSet>
            <relocations>
              <relocation>
                <pattern>com.google</pattern>
                <shadedPattern>com.qubole.shaded.google</shadedPattern>
              </relocation>
            </relocations>
          </configuration>
        </execution>
      </executions>
    </plugin>

    <plugin>
      ...
    </plugin>
  </plugins>
</build>