Code Obfuscation with ProGuard and JAXB

published: ⏰ 3

ProGuard is a powerful tool that not only obfuscates code but also optimizes it by removing unused classes, methods, and fields. This helps reduce the size of the final application and makes reverse engineering your code more difficult.

JAXB, on the other hand, provides a simple way to convert Java objects to XML and back. However, using JAXB can result in some classes and methods remaining accessible externally, which may be undesirable from a security perspective.

In this short note, I will show you how to configure ProGuard so that it works correctly with JAXB.

Main Problems When Using ProGuard with JAXB

Obfuscating code with JAXB requires special attention because JAXB uses reflection to access fields and methods of classes. If ProGuard renames these elements or removes them, JAXB will not work correctly with your objects.

The same applies to enums and annotations, which can also be damaged during obfuscation. With the enabled optimization !class/unboxing/enum ( see ProGuard documentation on optimizations), part of the enums may be replaced with numeric constants.

Configuring ProGuard to Work with JAXB

To solve the problem of renaming classes and attributes, it is sufficient to use standard annotations specifying the actual names of elements and attributes. For example:

Java

@XmlType(name = "documentType")
@XmlRootElement(name = "document")  // <1>
public final class Document {

    @XmlElement(name = "name")      // <2>
    private String name;

    @XmlElement(name = "type")
    private Type type;

    @XmlEnum
    @XmlType(name = "sourceType")
    public enum Source {
        LOCAL,
        REMOTE
    }
}
  1. Defines the name of the root XML element.
  2. Defines the name of the XML element for the name field.

During deserialization and serialization, JAXB will use the names specified in annotations, not those renamed by ProGuard.

To ensure that ProGuard correctly handles classes used by JAXB, you need to add corresponding rules to the configuration file.

HTML
-optimizations !class/unboxing/enum # <1>

-keepattributes InnerClasses,Signature,LineNumberTable,*Annotation*,EnclosingMethod # <2>
-keepclassmembers enum com.test.jaxb.** { # <3>
<fields>; # <4>
    public static **[] values();
    public static ** valueOf(java.lang.String);
    }
  1. Disables the optimization that can cause problems with enums.
  2. Keeps attributes necessary for JAXB to work.
  3. Keeps class members of the enum in the specified package.
  4. Keeps all fields of the enum.

Additional – Java SPI

In case of using Java SPI there may also be problems due to ProGuard optimizations and class renaming. Lists of available services are stored in META-INF/services/ resources and it is important that the interface name matches the full class name.

To prevent ProGuard from renaming SPI interfaces, you need to specify them in the configuration file. For example:

HTML
-keepnames class com.test.spi.HardwareMemoryProvider // <1>
  1. It is enough to save the full path to the class.

Conclusion

Using ProGuard for optimization and reducing the size of JAR can lead to problems when working with JAXB and Java SPI. However, by specifying appropriate rules, you can avoid these issues.

Proguard Jaxb