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):
And if I try obtain fields, they are listed obfuscated as a, b, c, d, e, f:
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()).
Enums are lists of constants. When you need a predefined list of values which do represent some kind of numeric or textual data, you should use an enum. You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values.
The enum declaration defines a class (called an enum type). The enum class body can include methods and other fields.
4) Adding new constants on Enum in Java is easy and you can add new constants without breaking the existing code.
Enums are a type and the enum name should start with a capital. Enum members are constants and their text should be all-uppercase.
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); }
This worked fine for me.
-keep public enum com.company.appname.**{ *; }
Where ** is package and subpackages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With