'Problems obfuscating with ProGuard an uberjar

I have built a fairly big framework around third party libraries like TestNG, Selenium and so on.
As a requirement I'm required to obfuscate the code before distributing it.
To distribute the code, I have to create a single jar with all it's dependencies, which I did without problems with maven-shade.
The problem begins when trying to do some light obfuscation, using ProGuard, on it which I have not obfuscating the jar without the dependencies (omiting the shade stage).

I'm using the following settings in the POM.

Shade stage

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.2.1</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <transformers>
            <transformerimplementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.mycompany.main.Init</mainClass>
          </transformer>
        </transformers>
        <minimizeJar>true</minimizeJar>
        <filters>
          <filter>
            <artifact>*:*</artifact>
            <excludes>
              <exclude>META-INF/*.SF</exclude>
              <exclude>META-INF/*.DSA</exclude>
              <exclude>META-INF/*.RSA</exclude>
            </excludes>
          </filter>
          <filter>
            <artifact>com.google.inject:guice</artifact>
            <includes>
              <include>**</include>
            </includes>
          </filter>
          <filter>
            <artifact>org.apache.xmlbeans:xmlbeans</artifact>
            <includes>
              <include>**</include>
            </includes>
          </filter>
          <filter>
            <artifact>org.freemarker:freemarker</artifact>
            <includes>
              <include>**</include>
            </includes>
          </filter>
          <filter>
            <artifact>org.apache.poi:poi-ooxml-schemas</artifact>
            <includes>
              <include>**</include>
            </includes>
          </filter>
        </filters>
      </configuration>
    </execution>
  </executions>
</plugin>

ProGuard stage

<plugin>
  <groupId>com.github.wvengen</groupId>
  <artifactId>proguard-maven-plugin</artifactId>
  <version>2.1.1</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>proguard</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <injar>${project.build.finalName}.jar</injar>
    <outjar>${project.build.finalName}-uber.jar</outjar>
    <inFilter>!META-INF/versions/9/**.class</inFilter>
    <options>
      <option>-dontshrink</option>
      <option>-keep class !com.mycompany.**,!com.mycompany.** { *; }</option>
      <option>-keep class io.**</option>
      <option>-keep class org.**</option>
      <option>-keep class com.google.**</option>
      <option>-keep class freemarker.**</option>
      <option>-keep class javax.**</option>
      <option>-keep class com.sun.**</option>
      <option>-keep class com.jacob.**</option>
      <option>-keep class net.**</option>
      <option>-keep class com.google.**</option>
      <option>-ignorewarnings</option>
      <option>-keepdirectories</option>
      <option>-dontnote</option>
      <option>-dontwarn org.**</option>
      <option>-dontwarn io.**</option>
      <option>-dontwarn com.fasterxml.**</option>
      <option>-dontwarn okio.**</option>
      <option>-dontwarn okhttp3.**</option>
      <option>-dontwarn freemarker.**</option>
      <option>-dontwarn com.microsoft.**</option>
      <option>-libraryjars ${java.home}/lib/rt.jar</option>
      <option>-libraryjars ${java.home}/lib/jce.jar</option>
      <option>-allowaccessmodification</option>
    </options>
    <obfuscate>true</obfuscate>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>net.sf.proguard</groupId>
      <artifactId>proguard-base</artifactId>
      <version>6.1.1</version>
    </dependency>
  </dependencies>
</plugin>

The returned Stacktrace (Partial)

[proguard] Warning: library class javax.mail.search.SearchException extends or implements program class javax.mail.MessagingException
[proguard] Warning: library class javax.mail.search.StringTerm extends or implements program class javax.mail.search.SearchTerm
[proguard] Warning: library class javax.mail.util.ByteArrayDataSource extends or implements program class javax.activation.DataSource
[proguard] Warning: library class javax.mail.util.SharedFileInputStream extends or implements program class javax.mail.internet.SharedInputStream
[proguard] Warning: there were 369 instances of library classes depending on program classes.
[proguard]          You must avoid such dependencies, since the program classes will
[proguard]          be processed, while the library classes will remain unchanged.
[proguard]          (http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)
[proguard] Unexpected error while performing partial evaluation:
[proguard]   Class       = [freemarker/ext/jsp/TagTransformModel]
[proguard]   Method      = [getWriter(Ljava/io/Writer;Ljava/util/Map;)Ljava/io/Writer;]
[proguard]   Exception   = [java.lang.IllegalArgumentException] (Can't find common super class of [freemarker/ext/jsp/JspWriterAdapter] (with 1 known super classes) and [java/io/Writer] (with 2 known super classes))
[proguard] Error: java.lang.IllegalArgumentException: Can't find common super class of [freemarker/ext/jsp/JspWriterAdapter] (with 1 known super classes) and [java/io/Writer] (with 2 known super classes)

I'm guessing that the problem resides in ProGuard trying to get the dependencies from outside of the .jar instead of using only the ones inside but I have no clue, and coulnd't found one, if there is a way of making ProGuard use the libraries inside on the uberjar or, maybe, I'm wrong with the way I'm trying to obfuscate the jar



Solution 1:[1]

I had the same issue within a larger Maven project.
I fixed it by adding javax.servlet.jsp so that Proguard could then find the missing superclass(es).
Due to my project nature, I added that as Maven dependency in pom.xml:

<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>javax.servlet.jsp-api</artifactId>
  <version>2.3.3</version>
  <scope>provided</scope>
</dependency>

TL;DR (how I got there)

  • Download the latest (at time of writing) freemarker-2.3.31-sources.jar from its mvn repo
  • explode its contents by jar xf freemarker-2.3.31-sources.jar console command
  • explore resulted tree to freemarker\ext\jsp\TagTransformModel.java
  • getWriter(Writer out, Map args) method uses JspWriter, coming from import javax.servlet.jsp at L31
  • It is available from its mvn repo, hence the newly included dependency in the solution above.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 01x4