John
John

Reputation: 11901

How to use Proguard to shrink Gradle ShadowJar output to create minimized fat Java jar?

I want to shrink a fat jar which has been created using the Gradle shadow plugin. The reason for this is that I need to keep some classes within a specific package within the finished jar as they are used for dynamic class generation (e.g. Class.forName(...)) and that plugin won't allow me to specify a package to keep when calling minimize() within the shadow jar task). I am therefore using the Proguard Gradle plugin.

buildscript {
    dependencies {
        classpath 'net.sf.proguard:proguard-gradle:6.2.2'
        classpath 'net.sf.proguard:proguard-base:6.2.2'
    }
}

plugins {
    id 'java-library'
    id 'application'
    id 'com.github.johnrengelman.shadow' version '5.2.0'
}

sourceCompatibility = 1.11

shadowJar {
    zip64 true
}

application {
    mainClassName = 'com.example.MyApp'
}

task proguard(type: proguard.gradle.ProGuardTask) {
    dependsOn shadowJar
    injars shadowJar

    outjars "${buildDir}/libs/${project.name}-${project.version}-proguard.jar"

    dontobfuscate
    dontoptimize
    keep 'class com.example.packagetokeep.*'

    // next block taken verbatim from Proguard's documentation examples:

    // Automatically handle the Java version of this build.
    if (System.getProperty('java.version').startsWith('1.')) {
        // Before Java 9, the runtime classes were packaged in a single jar file.
        libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
    } else {
        // As of Java 9, the runtime classes are packaged in modular jmod files.
        libraryjars "${System.getProperty('java.home')}/jmods/java.base.jmod", jarfilter: '!**.jar', filter: '!module-info.class'
    }
}

So, what I am trying to do is create a fat jar with all dependencies in it, then pass to Proguard to minimize. For now, I don't want to optimise or obfuscate.

When I try to run the task, I get a lot of errors of the form can't find referenced class for classes like javax.xml.stream.events.Attribute, java.sql.Timestamp, java.util.logging.Level. I think it's because Proguard is not picking up the Java runtime libraries. Here is the error summary:

Warning: there were 75920 unresolved references to classes or interfaces.
         You may need to add missing library jars or update their versions.
         If your code works fine without the missing classes, you can suppress
         the warnings with '-dontwarn' options.
         (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: there were 670 unresolved references to program class members.
         Your input classes appear to be inconsistent.
         You may need to recompile the code.
         (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
Warning: there were 4 unresolved references to library class members.
         You probably need to update the library versions.
         (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedlibraryclassmember)

How do I make Proguard work with Gradle and Java 11?

Upvotes: 4

Views: 1239

Answers (1)

bsautner
bsautner

Reputation: 4822

There are two parts to this in regards to shrinking a fat jar made with

com.github.johnrengelman.shadow

First, shadow has a shrink task that'll do most of what you probably are trying to do with progaurd:

tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {   
    minimize() {
        exclude(dependency("ch.qos.logback:.*:.*")) //for example to keep this
    }
}

If you still want to use progaurd the next step is to do as @xeruf suggested in the comments and use the block of libraryjars in the code snippet instead of one directive.

Upvotes: 0

Related Questions