Shading a transitive dependency (guava) with Maven Shading Plugin

Viewed 1351

I am trying to create a library that will be reused by applications that run on a WebServer equivalent.

The library will use Selenium (v3.9.1) which has a dependency on Guava (v23.6-jre), however, the WebServer also has Guava on the classpath and therefore I am getting a dependency conflict. When I include my library in an app and run it I get the following error:

    com.google.common.base.Preconditions.checkState(ZLjava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V (java.lang.NoSuchMethodError). (org.mule.api.MessagingException)
org.openqa.selenium.remote.service.DriverService.findExecutable(DriverService.java:124)
      org.openqa.selenium.chrome.ChromeDriverService.access$000(ChromeDriverService.java:32)
      org.openqa.selenium.chrome.ChromeDriverService$Builder.findDefaultExecutable(ChromeDriverService.java:137)
      org.openqa.selenium.remote.service.DriverService$Builder.build(DriverService.java:339)
      org.openqa.selenium.chrome.ChromeDriverService.createDefaultService(ChromeDriverService.java:88)
      org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:157)

As I can't change the dependencies on the server itself, I thought of using the Maven Shading Plugin to create an uber jar and relocating the guava classes - with the plugin configured as follows:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <artifactSet>
                    <includes>
                        <include>com.google.guava</include>
                        <include>org.seleniumhq.selenium</include>
                    </includes>
                </artifactSet>
                <relocations>
                    <relocation>
                         <pattern>com.google.common</pattern>
                     <shadedPattern>shaded.com.google.common</shadedPattern>
                    </relocation>
               </relocations>
           </configuration>
           <executions>
               <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
               </execution>
           </executions>
          </plugin>
     </plugins>
</build>

So, I believe this is saying:

  • Include guava and selenium in my FAT JAR.
  • Relocate all references to com.google.common to shaded.com.google.common.

This produces the JAR and if I unzip it, I can see the google libraries are shaded. However, when I run the application, I get the following error:

org.openqa.selenium.remote.service.DriverService$Builder.createArgs()Lshaded/com/google/common/collect/ImmutableList; (java.lang.AbstractMethodError).

Which suggests to me that the Selenium DriverService$Builder class and/or the Abstract method it refers to weren't updated during the relocation.

I can get it to work if I relocate both the google libraries AND the selenium libraries

<relocations>
    <relocation>
        <pattern>com.google.common</pattern>
        <shadedPattern>shaded.com.google.common</shadedPattern>
    </relocation>
    <relocation>
        <pattern>org.openqa.selenium</pattern>
        <shadedPattern>shaded.org.openqa.selenium</shadedPattern>
    </relocation>
</relocations>

However, this means that in my application (that makes use of the library), I need to refer to the Selenium classes under the "shaded" package. i.e. import shaded.org.openqa.selenium.WebDriver;

Is there anyway I can just shade the Guava dependencies but leave the Selenium libraries alone?

Any help much appreciated, Iain

0 Answers
Related