Back to blogs

Taylor Brooks Compatibility

Keeping Reflection Safe with @KeepName and @KeepSignature

Renaming is the transformer most likely to break code that finds its own names at runtime: reflection, serialization, JSON mappers. HashGuard gives you two ways to say what must stay, inline annotations from the :api module and exclude rules in the config.

Declare intent in the code

The :api module is a thin jar that only depends on the ASM tree API. Add it to the client as compileOnly; its annotations are stripped from the output jar automatically, so they do not ship.

The four annotations java
import fr.polargames.api.annotation.*;@KeepNamepublic class PublicApi { }            // class and member names preserved (reflection, serialization)class Controller {    @KeepSignature    void route(String id) { }         // method signature + MethodParameters names preserved}@NoObfuscationclass Sensitive { }                   // excluded from every transformer@ExcludeTransformers({ Transformers.CONTROL_FLOW, Transformers.FLATTEN })void hotPath() { }                    // excluded from specific transformers only

Which one to reach for

  • @KeepName keeps the names of a class and its members.
  • @KeepSignature keeps a method signature and its MethodParameters names.
  • @NoObfuscation excludes a class from every transformer.
  • @ExcludeTransformers excludes from the transformers you name only. Transformers holds one string constant per token, plus Transformers.GLOBAL to exclude everything at once.

Exclude rules in the config

When you cannot annotate the code, for example in generated classes, use the exclude string of the config. It holds one rule per line in the form [<token>:][!]<pattern>.

  • No token prefix means the rule applies to all transformers.
  • ! re-includes a pattern inside a broader exclusion.
  • Wildcards are *seg for a prefix or suffix and ** for any depth.
  • To exclude a class and all its members, write pkg.ClassName**.
Two rules, scoped by token json
"exclude": "flatten:net.minecraft.**\nrename:Start**"

A ready-made preset for Minecraft 1.7.10 lives at presets/mc-1.7.10.exclude.

  1. 01 @KeepName Keep names on one class or member
  2. 02 @KeepSignature Keep one method signature and its parameter names
  3. 03 exclude rules Scope by token and pattern in the config
Three layers, from the most local to the most global.

Safe defaults already in place

  • access skips fields annotated with @SerializedName, which keeps Gson 2.14+ deserialization working.
  • shuffleOptions.methodParameters is false by default, for reflection safety.

Decoding stack traces

mappingOutput writes an old-name to new-name mapping JSON. You can use it to decode obfuscated stack traces in JProfiler or any other tooling.