Class DynamicSelectorDesc

  • All Implemented Interfaces:
    ITargetSelector, ITargetSelectorByName, ITargetSelectorDynamic

    public class DynamicSelectorDesc
    extends java.lang.Object
    implements ITargetSelectorDynamic, ITargetSelectorByName
    A Target Selector which matches candidates using descriptors contained in @Desc annotations. The descriptor annotations may be local, or may be applied to the method or even the owning mixin using user-specified ids, or implicit coordinates based on the relative location of the consumer. eg. an @At annotation and the @Desc annotation itself, which might be on a parent element for convenience.

    See @Desc for the specific syntax of descriptor annotations.

    Local Descriptors

    Some annotations can use @Desc selectors directly, namely @At (specified in @At.desc) and all Injector annotations (specified in target - for example @Inject.target). In these cases it is not necessary to specify an id for the descriptor since the usage is inferred from context.

    Resolved Descriptors

    Descriptors can also be placed as annotations on the mixin method or the mixin class, thus allowing descriptors to be re-used by multiple consumers. For example where several injectors target the same method, the descriptor can be placed on the mixin itself and consumed by id. In this situation it is necessary to specify an id for the descriptor and specify the chosen id as a selector string:

    @Mixin(TargetClass.class)
    @Desc(id = "foo", value = "getFoo", args = { int.class })
    abstract class MyMixin {

        @Inject(target = "@Desc(foo)", at = @At("RETURN"))
        void myHandlerMethod(int arg, CallbackInfo ci) {
          ...
        }

    }

    Note that the id string can be anything you wish, but is matched case-insensitively and must be non-empty, so feel free to be as descriptive as you wish.

    Implicit coordinates

    As an alternative to specifying an explicit descriptor id for descriptors, it is also possible to use implicit coordinates generated using the location of the consumer. To do so, use the selector "@Desc" with no arguments and give the descriptor an id which corresponds to the coordinate of the consumer:

    In this example, the coordinate of the @At annotation, "at" is used as the descriptor id.

        @Desc(id = "at", value = "theMethodName", args = { String.class }, ret = boolean.class)
        @Inject(method = "targetMethod()V", at = @At(value = "INVOKE" target = "@Desc"))
        void myHandlerMethod(int arg, CallbackInfo ci) {
          ...
        }

    As the resolver widens its search it adds new components to the start of the implicit coordinate which match the element, separated by dots. For example @At annotations inside a @Slice will first resolve as (local coordinate) from, followed by slice.from, and finally handlerMethodName.slice.from. This allows implicit coordinates to be used up to the mixin level as in the first example.

    @Mixin(TargetClass.class)
    @Desc(id = "myHandlerMethod.at", value = "theMethodName", args = { String.class }, ret = boolean.class)
    @Desc(id = "myHandlerMethod.method", value = "getFoo", args = { int.class })
    abstract class MyMixin {

        @Inject(method = "@Desc", at = @At(value = "INVOKE" target = "@Desc"))
        void myHandlerMethod(int arg, CallbackInfo ci) {
          ...
        }

    To view the coordinates used to resolve the descriptor for a particular element, use the special id "?" in the selector:

        @Inject(method = "@Desc", at = @At(value = "INVOKE" target = "@Desc(?)"))
        void myHandler(int arg, CallbackInfo ci) {

    This will cause the resolver to pretty-print the considered coordinates and elements into the console:

    /*****************************************************/
    /* Coordinate    Search Element       Detail         */
    /*****************************************************/
    /* at            @At                  @At.desc       */
    /* at            myHandler            method         */
    /* myhandler.at  mixins.json:MyMixin  mixin          */
    /* myhandler.at  @Redirect            @Redirect.desc */
    /* myhandler.at  myhandler            method         */
    /*****************************************************/

    Don't worry that some combinations of coordinate and element are not possible (for example there is no member desc on @At). The resolver doesn't know that and scans each visited element for members it supports.

    • Constructor Detail

      • DynamicSelectorDesc

        protected DynamicSelectorDesc​(InvalidSelectorException ex,
                                      java.lang.String id,
                                      org.objectweb.asm.Type owner,
                                      java.lang.String name,
                                      org.objectweb.asm.Type[] args,
                                      org.objectweb.asm.Type returnType,
                                      Quantifier matches,
                                      java.util.List<IAnnotationHandle> next,
                                      boolean disabled)
    • Method Detail

      • parse

        public static DynamicSelectorDesc parse​(java.lang.String input,
                                                ISelectorContext context)
        Parse a descriptor selector from the supplied input. The input is treated as a descriptor id to be resolved, or if empty uses implicit coordinates from the selection context
        Parameters:
        input - ID string, can be empty
        context - Selector context
        Returns:
        parsed selector
      • resolve

        public static DynamicSelectorDesc resolve​(ISelectorContext context)
        Resolve a descriptor selector from the supplied context only, implicit coordinates are used.
        Parameters:
        context - Selector context
        Returns:
        parsed selector
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object
      • getId

        public java.lang.String getId()
      • getArgs

        public org.objectweb.asm.Type[] getArgs()
      • getReturnType

        public org.objectweb.asm.Type getReturnType()
      • next

        public ITargetSelector next()
        Description copied from interface: ITargetSelector
        Get the next target selector in this path (or null if this selector is the last selector in the chain. Called at recurse points in the subject in order to match against the child subject.

        Can return null

        Specified by:
        next in interface ITargetSelector
      • configure

        public ITargetSelector configure​(ITargetSelector.Configure request,
                                         java.lang.String... args)
        Description copied from interface: ITargetSelector
        Configure and return a modified version of this selector by consuming the supplied arguments. Results from this method should be idempotent in terms of the configuration of the returned object, but do not have to necessarily return the same object if the callee already matches the supplied configuration, or if the requested mutation is not supported by the selector, though this is generally the case.

        In other words, calling configure(Configure.ORPHAN) when this object is already an orphan or does not support orphaning, may simply return this object, or might return an identically-configured copy.

        Must not return null, defaults to returning unmodified selector.

        Specified by:
        configure in interface ITargetSelector
        Parameters:
        request - Requested operation
        args - Configuration arguments
        Returns:
        Configured selector, may return this selector if the specified condition is already satisfied
      • matches

        public MatchResult matches​(java.lang.String owner,
                                   java.lang.String name,
                                   java.lang.String desc)
        Description copied from interface: ITargetSelectorByName
        Test whether this selector matches the supplied values. Null values are ignored.
        Specified by:
        matches in interface ITargetSelectorByName
        Parameters:
        owner - Owner to compare with, null to skip
        name - Name to compare with, null to skip
        desc - Signature to compare with, null to skip
        Returns:
        true if all non-null values in this reference match non-null arguments supplied to this method
      • match

        public <TNode> MatchResult match​(ElementNode<TNode> node)
        Description copied from interface: ITargetSelector
        Test whether this selector matches the supplied element node
        Specified by:
        match in interface ITargetSelector
        Type Parameters:
        TNode - node type
        Parameters:
        node - node node to test
        Returns:
        true if this selector can match the supplied field