0

I have a uber jar that's already generated (not via Maven; I just have the jar). I need to use it along with another jar, which has dependency conflicts. I'd like to shade all the libs in the first uber jar, except for a few classes which need to be public.

What is the setup to take an existing jar, and use Maven shade plugin to rename most (except for a whitelist) of its classes, generating a new uber jar?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
SRobertJames
  • 8,210
  • 14
  • 60
  • 107

1 Answers1

2

You can do a "rename-all" type of activity with maven-shade-plugin. For example:

<relocations>
  <relocation>
    <pattern></pattern>
    <shadedPattern>relocated.</shadedPattern>
    <excludes>
      <exclude>com.myfirm.level1.level2.*</exclude>                   
    </excludes>
  </relocation>
</relocations>

Will essentially move every package a.b.c to relocated.a.b.c (except for the explicit pattern I excluded).

It appears that the relocation process moves all references to classes that match that pattern, regardless if that class is defined within a dependency used to construct the jar.

The following stack trace (obtained from trying to run a main() defined in a jar that was constructed using the relocation above) shows that a reference to java.lang.Object was renamed to relocated.java.lang.Object, and that (obviously) the relocated. version can't be found.

java.lang.NoClassDefFoundError: relocated/java/lang/Object
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
Caused by: java.lang.ClassNotFoundException: relocated.java.lang.Object
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 13 more
Exception in thread "main"
  • Why will this be unusable? As long as that class isn't accessed outside the Jar, won't shade modify the bytecode to use `relocated.a.b.c`? – SRobertJames Jul 09 '14 at 00:55
  • If you look at the stack trace, it appears the the relocation 'edits' references to types that not defined within the jar. So, the reference to `java.lang.Object` gets changed to `relocated.java.lang.Object` which doesn't exist on the class path. I'm going to edit this answer to make this a bit clearer. – dan.m was user2321368 Jul 09 '14 at 14:52