Hubbitus Hubbitus - 4 months ago 25
Java Question

How to tell proguard to keep enum constants and fields

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()).

Answer

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

-keepclassmembers class * extends java.lang.Enum {
    <fields>;
    public static **[] values();
    public static ** valueOf(java.lang.String);
}