I’m attempting to use ProGuard to slim down the jar on an existing project with a lot of known extraneous includes.
If I run with -optimizationpasses 1 things run, but the resulting jar is 42,474,328 (down from 42,483,405 for the unproguarded jar) which is an improvement, but well below expectation (a prior hand-crafted approach had the jar down to 16,465,699, so my expectation/hope is that proguard should be able to do that or better)
Bumping things to -optimizationpasses 2 I get the following error:
[proguard] Unexpected error while evaluating instruction:
[proguard] Class = [org/apache/logging/log4j/core/jmx/Server]
[proguard] Method = [reregisterMBeansAfterReconfigure()V]
[proguard] Instruction = [291] invokestatic #39 = Methodref(org/apache/logging/log4j/core/jmx/Server.register(Ljavax/management/MBeanServer;Ljava/lang/Object;Ljavax/management/ObjectName;)V)
[proguard] Exception = [proguard.evaluation.IncompleteClassHierarchyException] (Can’t find common super class of [org.apache.logging.log4j.core.jmx.StatusLoggerAdmin] (with 1 known super classes: org.apache.logging.log4j.core.jmx.StatusLoggerAdmin) and [org.apache.logging.log4j.core.jmx.LoggerContextAdmin] (with 1 known super classes: org.apache.logging.log4j.core.jmx.LoggerContextAdmin))
[proguard] Unexpected error while performing partial evaluation:
[proguard] Class = [org/apache/logging/log4j/core/jmx/Server]
[proguard] Method = [reregisterMBeansAfterReconfigure()V]
[proguard] Exception = [proguard.evaluation.IncompleteClassHierarchyException] (Can’t find common super class of [org.apache.logging.log4j.core.jmx.StatusLoggerAdmin] (with 1 known super classes: org.apache.logging.log4j.core.jmx.StatusLoggerAdmin) and [org.apache.logging.log4j.core.jmx.LoggerContextAdmin] (with 1 known super classes: org.apache.logging.log4j.core.jmx.LoggerContextAdmin))
[proguard] Unexpected error
[proguard] java.lang.RuntimeException:
[proguard]
[proguard] It appears you are missing some classes resulting in an incomplete class hierarchy,
[proguard] please refer to the troubleshooting page in the manual:
[proguard] ProGuard Manual: Troubleshooting | Guardsquare
[proguard]
[proguard] at proguard.ProGuard.execute(ProGuard.java:256) ~[proguard-base-7.2.2.jar:7.2.2]
[proguard] at proguard.ProGuard.main(ProGuard.java:623) [proguard-base-7.2.2.jar:7.2.2]
I’ve tried multiple permutations of -libraryjars and -injars pointing to a local copy of the correct version of log4j-core.jar to no effect/no change in the resulting error.
I also tried -addconfigurationdebugging but it provided no additional information that I could notice.
Proguard configuration:
<proguardVersion>7.2.2</proguardVersion>
<obfuscate>true</obfuscate>
<attach>true</attach>
<appendClassifier>false</appendClassifier>
<addMavenDescriptor>true</addMavenDescriptor>
<injar>bootstrap.jar</injar>
<injarNotExistsSkip>true</injarNotExistsSkip>
<libs>
<lib>${java.home}/jmods/java.base.jmod</lib>
</libs>
<options>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
</option>
<option>-allowaccessmodification</option>
<option>-keep public class com.company.bootstrap.DeploymentBootstrapApp { *; }</option>
<option>-keep class picocli.CommandLine { *; }</option>
<option>-keep class picocli.CommandLine$* { *; }</option>
<!-- to solve can't find referenced class warnings -->
<option>-dontwarn java.lang.**</option>
<option>-dontwarn com.sun.**</option>
<option>-ignorewarnings</option>
<!-- dagger1 does not play nice with obfuscation, remove when/if datacollector is upgraded -->
<option>-dontobfuscate</option>
<!-- gives better errors -->
<option>-verbose</option>
<!-- shrink more -->
<option>-optimizationpasses 2</option>
<option>-overloadaggressively</option>
<option>-mergeinterfacesaggressively</option>
</options>
</configuration>
First of all, welcome to our community & thanks for sharing your current problem.
The error you should fix is related to the fact that certain classes have been removed while they should not have been. Specifically the superclasses ProGuard could not found should be kept:
-keep class org.apache.logging.log4j.core.jmx.StatusLoggerAdmin {*;}
-keep class org.apache.logging.log4j.core.jmx.LoggerContextAdmin {*;}
Thank you for the response, that pair of keeps did not change anything insofar as errors are concerned.
I also tried adding a keep for javax.management.NotificationBroadcasterSupport (the shared super class), and even went so far as to do a -keep interface for every interface eiter of the class implements and… still the exact same error.
current keeps:
Based on your configuration file, my initial assessment was wrong. My apologies for that. Can you please carefully read through the following? The answer to your problem depends on your specific use case but the info above should allow you to resolve the issue:
Warning: can’t find referenced class
A class in one of your program jars or library jars is referring to a class or interface that is missing from the input. The warning lists both the referencing class(es) and the missing referenced class(es). There can be a few reasons, with their own solutions:
If the missing class is referenced from your own code, you may have forgotten to specify an essential library. Just like when compiling all code from scratch, you must specify all libraries that the code is referencing, directly or indirectly. If the library should be processed and included in the output, you should specify it with -injars, otherwise you should specify it with -libraryjars. For example, if ProGuard complains that it can’t find a java.lang class, you have to make sure that you are specifying the run-time library of your platform. For JSE, these are typically packaged in lib/rt.jar (vm.jar for IBM’s JVM, and classes.jar in MacOS X) or as of Java 9, jmods/java.base.jmod.
If the missing class is referenced from a pre-compiled third-party library, and your original code runs fine without it, then the missing dependency doesn’t seem to hurt. The cleanest solution is to filter out the referencing class or classes from the input, with a filter like “-injars myapplication.jar(!somepackage/SomeUnusedReferencingClass.class)”. DexGuard will then skip this class entirely in the input, and it will not bump into the problem of its missing reference. However, you may then have to filter out other classes that are in turn referencing the removed class. In practice, this works best if you can filter out entire unused packages at once, with a wildcard filter like “-libraryjars mylibrary.jar(!someunusedpackage/**)”.
If you don’t feel like filtering out the problematic classes, you can try your luck with the -ignorewarnings option, or even the -dontwarn option. Only use these options if you really know what you’re doing though.
Error: Can’t find any super classes of … (not even immediate super class …) Error: Can’t find common super class of … and …
It seems like you tried to avoid the warnings from the previous paragraph by specifying -ignorewarnings or -dontwarn, but it didn’t work out. ProGuard’s optimization step and preverification step really need the missing classes to make sense of the code. Preferably, you would solve the problem by adding the missing library, as discussed. If you’re sure the class that references the missing class isn’t used either, you could also try filtering it out from the input, by adding a filter to the corresponding -injars option: “-injars myapplication.jar(!somepackage/SomeUnusedClass.class)”. As a final solution, you could switch off optimization (-dontoptimize) and preverification (-dontpreverify).
I attempted to add the library first as java.logging.jmod, then as the explicit versioned jar… in both cases this results in proguard throwing out:
[proguard] ProGuard, version 7.2.2
[proguard] Unexpected error
[proguard] java.io.IOException: The same input jar [/Users/mcrampon/.m2/repository/org/apache/logging/log4j/log4j-core/2.17.2/log4j-core-2.17.2.jar] is specified twice.
[proguard] at proguard.ConfigurationChecker.checkConflicts(ConfigurationChecker.java:220) ~[proguard-base-7.2.2.jar:7.2.2]
[proguard] at proguard.ConfigurationChecker.check(ConfigurationChecker.java:89) ~[proguard-base-7.2.2.jar:7.2.2]
[proguard] at proguard.ProGuard.checkConfiguration(ProGuard.java:290) ~[proguard-base-7.2.2.jar:7.2.2]
[proguard] at proguard.ProGuard.execute(ProGuard.java:99) ~[proguard-base-7.2.2.jar:7.2.2]
[proguard] at proguard.ProGuard.main(ProGuard.java:623) [proguard-base-7.2.2.jar:7.2.2]
same result if I do a -libraryjars pointing at the jar which puts me back to being at a total loss as to why ProGuard can’t find those two logging classes/how to resolve the issue.
Note, also, that the build pattern is that I am doing a full “build with dependencies” then passing that jar to proguard to minimize, so everything (and more) should be available just in the jar ProGuard is being handled, and I’m looking for ProGuard to do the work of stripping out all the excess.
If I omit the ignorewarnings flag I am facing 17413 unresolved references to classes or interfaces and 226 unresolved reference to program class members.
the entire purpose for which I’m attempting to use ProGuard is for optimization/jar minification, so optimization is explicitly what I want/need.