31

I've try obfuscate our web application which use spring, jaxb and relies on annotations, and reflection heavily. I apply many recipes found in internet to keep some classes, attributes, annotations and enumerations. But with enumerations still have problem. I've able preserve enum constants apply configuration from http://proguard.sourceforge.net/manual/examples.html#enumerations:

-keepclassmembers,allowoptimization enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

At first glance it looks like working solution and constant preserved, so (Class.getEnumConstants()) return correct list of values. But I got NoSuchFieldException when I try retrieve field by any of that by name.

Problem come from jaxb reflection navigator, please look at code:

public Field[] getEnumConstants(Class clazz) {
    try {
        Object[] values = clazz.getEnumConstants();
        Field[] fields = new Field[values.length];
        for (int i = 0; i < values.length; i++) {
            fields[i] = clazz.getField(((Enum) values[i]).name());
        }
        return fields;
    } catch (NoSuchFieldException e) {
        // impossible
        throw new NoSuchFieldError(e.getMessage());
    }
}

I fall exactly into "impossible" branch. I think it will be easy understandable to look at debug session screenshot (there also listed constants): Screenshot of debug session1

And if I try obtain fields, they are listed obfuscated as a, b, c, d, e, f: Screenshot of debug session2

My proguard configuration now look like (strip out some library listing and kipp particular classes, fields and methods about proguard complain):

-injars  core-3.15.rc5.6.jar
-outjars core-3.15.rc5.6.proguard.jar

-libraryjars <java.home>/lib/rt.jar

-libraryjars ... # Other libs listed, strip out for shortness

-printmapping core-3.15.rc5.6.proguard.map

-keep public class ru.rlh.egais.portal.backend.controller.rest.**
-keep public class ru.rlh.egais.portal.backend.integration.soap.service.**

# http://midgetontoes.com/blog/2015/06/26/tips-for-using-proguard-with-spring-framework
-optimizations !class/marking/final

-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF,META-INF/spring.*,spring/*

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# Also tried:
# -keepattributes **

-allowaccessmodification
-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-keepdirectories
-keep @org.springframework.transaction.annotation.Transactional class *
-keep @org.springframework.stereotype.Service class *
-keep @org.springframework.stereotype.Repository class *
-keep @org.springframework.stereotype.Controller class *
-keep @org.springframework.stereotype.Component class *
-keep @org.springframework.beans.factory.annotation.Autowired class *
-keep @org.springframework.web.bind.annotation.ResponseBody class *
-keep @org.springframework.web.bind.annotation.RequestMapping class *
-keep @org.springframework.stereotype.Repository class *
-keep @javax.annotation.Resource class *
-keep @org.springframework.cache.annotation.EnableCaching class *
-keep @org.springframework.context.annotation.Configuration class *

-keepclassmembers class * {
    @org.springframework.beans.factory.annotation.* *;
    @org.springframework.beans.factory.annotation.Qualifier *;
    @org.springframework.beans.factory.annotation.Value *;
    @org.springframework.beans.factory.annotation.Required *;
    @org.springframework.context.annotation.Bean *;
    @javax.annotation.PostConstruct *;
    @javax.annotation.PreDestroy *;
    @org.aspectj.lang.annotation.AfterReturning *;
    @org.aspectj.lang.annotation.Pointcut *;
    @org.aspectj.lang.annotation.AfterThrowing *;
    @org.aspectj.lang.annotation.Around *;
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

So, my question how I could fully keep public enums from obfuscation? In both cases - use its constants (class.getEnumConstants()) and fields (class.getFields()).

Hubbitus
  • 5,161
  • 3
  • 41
  • 47

2 Answers2

76

Thanks to http://sourceforge.net/p/proguard/discussion/182455/thread/1c28f199/ I found solution for my question (<⁠fields> must be added):

-keepclassmembers class * extends java.lang.Enum {
    <fields>;
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
Hubbitus
  • 5,161
  • 3
  • 41
  • 47
  • 1
    For anyone who comes across this and wants the ant equivalent: Add __ to your proguard task. – Paul Wagland Sep 01 '17 at 13:30
  • I suppose you speak about `maven` task configuration? There nothing about maven in initial question. I use `gradle`, but it also out of scope. So, all configuration provided in answers belongs to `proguard.conf` syntax. – Hubbitus Sep 04 '17 at 09:52
  • Hubbitus yes, however I found this answer as the third link while trying to solve exactly this problem, but using ant (not maven), and not using proguard directly. The translation between the two is not immediately obvious, at least not to me, so I added a comment so that anyone else who finds this under my conditions would also have the additional information. It was in no way meant to imply that your answer was incorrect or incomplete. I regret if that is the inference that you took. – Paul Wagland Sep 04 '17 at 17:10
  • Also see [ProGuard docs - Processing enumeration classes](https://www.guardsquare.com/en/proguard/manual/examples#enumerations). - For Android projects these settings can be loaded via referencing *proguard-android.txt* in *build.gradle*. – JJD Oct 11 '17 at 11:08
18

This worked fine for me.

-keep public enum com.company.appname.**{
    *;
}

Where ** is package and subpackages.

Joma
  • 3,520
  • 1
  • 29
  • 32
  • Perfect answer. – odifek Jul 01 '21 at 08:12
  • Thanks @Joma. After the Android Gradle Plugin update all of my hand made public enum classes on the project were crashing the app at run time. That was pretty annoying. But your _"Proguard, do not touch on my enum classes"_ is working amazingly. – Thiengo Dec 16 '22 at 16:14