public class DynamicSelectorDesc extends java.lang.Object implements ITargetSelectorDynamic, ITargetSelectorByName
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.
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.
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.
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.
ITargetSelectorDynamic.SelectorAnnotation, ITargetSelectorDynamic.SelectorIdITargetSelector.Configure| Modifier | Constructor and Description |
|---|---|
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) |
| Modifier and Type | Method and Description |
|---|---|
ITargetSelector |
attach(ISelectorContext context)
Attach this selector to the specified context.
|
ITargetSelector |
configure(ITargetSelector.Configure request,
java.lang.String... args)
Configure and return a modified version of this selector by consuming the
supplied arguments.
|
org.objectweb.asm.Type[] |
getArgs() |
java.lang.String |
getDesc()
Get the member descriptor, can be null
|
java.lang.String |
getId() |
int |
getMaxMatchCount()
Maximum number of candidates this selector can match
|
int |
getMinMatchCount()
Minimum number of candidates this selector must match
|
java.lang.String |
getName()
Get the member name, can be null
|
java.lang.String |
getOwner()
Get the member owner, can be null
|
org.objectweb.asm.Type |
getReturnType() |
<TNode> MatchResult |
match(ElementNode<TNode> node)
Test whether this selector matches the supplied element node
|
MatchResult |
matches(java.lang.String owner,
java.lang.String name,
java.lang.String desc)
Test whether this selector matches the supplied values.
|
ITargetSelector |
next()
Get the next target selector in this path (or null if this
selector is the last selector in the chain.
|
protected ITargetSelector |
next(int index) |
static DynamicSelectorDesc |
of(IAnnotationHandle desc,
ISelectorContext context)
Convert the supplied annotation into a selector instance
|
static DynamicSelectorDesc |
of(IResolvedDescriptor desc)
Convert the supplied annotation into a selector instance
|
static DynamicSelectorDesc |
parse(IAnnotationHandle desc,
ISelectorContext context)
Convert the supplied annotation into a selector instance
|
static DynamicSelectorDesc |
parse(java.lang.String input,
ISelectorContext context)
Parse a descriptor selector from the supplied input.
|
static DynamicSelectorDesc |
resolve(ISelectorContext context)
Resolve a descriptor selector from the supplied context only, implicit
coordinates are used.
|
java.lang.String |
toDescriptor()
Get a representation of this selector as a complete descriptor
|
java.lang.String |
toString() |
ITargetSelector |
validate()
Perform basic sanity-check validation of the selector, checks that the
parsed out parameters are basically sane
|
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)
public static DynamicSelectorDesc parse(java.lang.String input, ISelectorContext context)
input - ID string, can be emptycontext - Selector contextpublic static DynamicSelectorDesc parse(IAnnotationHandle desc, ISelectorContext context)
context - Selector contextdesc - Annotation to parsepublic static DynamicSelectorDesc resolve(ISelectorContext context)
context - Selector contextpublic static DynamicSelectorDesc of(IAnnotationHandle desc, ISelectorContext context)
desc - Annotation to parsecontext - Selector contextpublic static DynamicSelectorDesc of(IResolvedDescriptor desc)
desc - Resolved descriptorpublic java.lang.String toString()
toString in class java.lang.Objectpublic java.lang.String getId()
public java.lang.String getOwner()
ITargetSelectorByNamegetOwner in interface ITargetSelectorByNamepublic java.lang.String getName()
ITargetSelectorByNamegetName in interface ITargetSelectorByNamepublic org.objectweb.asm.Type[] getArgs()
public org.objectweb.asm.Type getReturnType()
public java.lang.String getDesc()
ITargetSelectorByNamegetDesc in interface ITargetSelectorByNamepublic java.lang.String toDescriptor()
ITargetSelectorByNametoDescriptor in interface ITargetSelectorByNamepublic ITargetSelector validate() throws InvalidSelectorException
ITargetSelectorvalidate in interface ITargetSelectorInvalidSelectorException - if any sanity check failspublic ITargetSelector next()
ITargetSelectorCan return null
next in interface ITargetSelectorprotected ITargetSelector next(int index)
public ITargetSelector configure(ITargetSelector.Configure request, java.lang.String... args)
ITargetSelectorIn 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.
configure in interface ITargetSelectorrequest - Requested operationargs - Configuration argumentspublic ITargetSelector attach(ISelectorContext context) throws InvalidSelectorException
ITargetSelectorInvalidSelectorException is thrown.attach in interface ITargetSelectorcontext - Context to attach toInvalidSelectorExceptionpublic int getMinMatchCount()
ITargetSelectorgetMinMatchCount in interface ITargetSelectorpublic int getMaxMatchCount()
ITargetSelectorgetMaxMatchCount in interface ITargetSelectorpublic MatchResult matches(java.lang.String owner, java.lang.String name, java.lang.String desc)
ITargetSelectorByNamematches in interface ITargetSelectorByNameowner - Owner to compare with, null to skipname - Name to compare with, null to skipdesc - Signature to compare with, null to skippublic <TNode> MatchResult match(ElementNode<TNode> node)
ITargetSelectormatch in interface ITargetSelectorTNode - node typenode - node node to test