Annotation Interface Shadow


@Target({METHOD,FIELD}) @Retention(RUNTIME) public @interface Shadow
Used to indicate a Mixin class member which is acting as a placeholder for a method or field in the target class
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    Supplies possible aliases for this shadow member.
    In general, shadow methods can be declared using their name in the target class as you would expect, however we run into a problem when we want to mix in a method with the same name and arguments, but a different return type to the shadow method.
    boolean
    By default, the annotation processor will attempt to locate an obfuscation mapping for all Shadow methods since it is anticipated that in general the target of a Shadow annotation will be an obfuscated field or method in the target class.
  • Element Details

    • prefix

      String prefix

      In general, shadow methods can be declared using their name in the target class as you would expect, however we run into a problem when we want to mix in a method with the same name and arguments, but a different return type to the shadow method. While the JVM itself will happily support methods with signatures that differ only on return type, the compiler itself does not. This poses a problem, since we have no way to leverage this behaviour since our mixin class will not compile.

      To circumvent this compiler limitation, the prefix option can be used. By specifying a prefix for the shadow method, it is subsequently possible to compile the mixin class, the specified prefix will then be stripped from the method name prior to applying the mixin, and everything will work as expected. You may either use the default prefix: "shadow$", or you may specify your own. It is good practice to specify the prefix if you are using it, regardless of whether you use the default or not. For example consider the intrinsic readability of the following snippets

      :
           @Shadow abstract void someMethod(int arg1, int arg2);
           @Shadow abstract void shadow$someMethod(int arg1, int arg2);
           @Shadow(prefix = "shadow$") abstract void shadow$someMethod(int arg1, int arg2);
           @Shadow(prefix = "foo$") abstract void foo$someMethod(int arg1, int arg2);
       

      All of these declarations are semantically equivalent, however the third and fourth are the most expressive in terms of making their intentions clear, and thus specifying prefix is recommended, since it aids readability and maintainability.

      Note that specifying a prefix does not enforce use of the prefix, the behaviour of prefix is such that the prefix will be stripped from the start of the method name as long as the method name actually starts with the prefix! This has important repercussions since if the annotation value does not match the method prefix then no renaming will take place likey resulting in a failure state indicated by an InvalidMixinException at run time.

      Prefixes on shadow fields are considered an error condition and don't have any purpose either way, since the scenario described above cannot actually occur with fields.

      Returns:
      the shadow prefix
      Default:
      "shadow$"
    • remap

      boolean remap
      By default, the annotation processor will attempt to locate an obfuscation mapping for all Shadow methods since it is anticipated that in general the target of a Shadow annotation will be an obfuscated field or method in the target class. However since it is possible to also apply mixins to non-obfuscated targets (or non- obfuscated methods in obfuscated targets, such as methods added by Forge) it may be desirable to suppress the compiler warning which would otherwise be generated. Setting this value to false will cause the annotation processor to skip this annotation when attempting to build the obfuscation table for the mixin.
      Returns:
      True to instruct the annotation processor to search for obfuscation mappings for this annotation
      Default:
      true
    • aliases

      String[] aliases
      Supplies possible aliases for this shadow member. This should only be used in the following scenarios:
      • When shadowing a sythetic field or method which can have different names at development time because it is regenerated by the compiler.
      • When another mod or transformer is known to change the name of a field

      Only private members may be given aliases. This is because aliases can only be calculated when the mixin is applied and thus would otherwise invalidate the calculated class metadata if another mixin had already been applied in the hierarchy.

      Returns:
      Aliases for this member
      Default:
      {}