Annotation Type Inject
-
@Target(METHOD) @Retention(RUNTIME) public @interface InjectSpecifies that this mixin method should inject a callback (or callbacks) to itself in the target method(s) identified bymethod().Callbacks are simple injectors which simply inject a call to the decorated method (the handler) in the target method (or methods) selected by the selectors specified in
method(). Callback Injectors can also capture arguments and local variables from the target for use in the handler.Callback handler methods should always return void and should have the same static-ness as their target (though it is allowable to have a static callback injected into an instance method, and for obvious reasons the inverse is not permitted).
Basic usage
The simplest usage of @Inject captures no context from the target scope. This is particularly useful if the injector is targetting multiple methods with different signatures. In this case only the
CallbackInfo(orCallbackInfoReturnableas appropriate) is required.private void onSomeEvent(CallbackInfo ci)
Capture target arguments
Callbacks can also capture the arguments passed to the target method. To do so specify the target arguments before the
CallbackInfo:private void onSomeEvent(int arg1, String arg2, CallbackInfo ci)
Surrogate methods
If injecting into multiple methods with different target arguments it is obviously possible to ignore the target arguments (see "Basic Usage" above) but this may be unsuitable if arguments from the target are required. If you need to inject into multiple methods but also wish to capture method arguments you may provide a surrogate method with the alternative signature. In fact you may provide as many surrogates as required by the injection. Surrogate methods much have the same name as the handler method and must be decorated with
Surrogate. A surrogate may also be required where the LVT of a method with local capture (see below) is known to change between different environments or injection points.Capture local variables
In addition to capturing the target method arguments, it may be desirable to capture locally-scoped variables from the target method at the point of injection. This is usually executed in two stages:
- Set the
locals()value of your injection toLocalCapture.PRINTand run the application. - When the injector is processed, a listing of the LVT is produced accompanied by a generated signature for your handler method including the discovered args. Modify your handler signature accordingly.
For more details see
locals(). - Set the
-
-
Required Element Summary
Required Elements Modifier and Type Required Element Description At[]atArray ofAtannotations which describe theInjectionPoints in the target method.
-
Optional Element Summary
Optional Elements Modifier and Type Optional Element Description intallowInjection points are in general expected to match every candidate instruction in the target method or slice, except in cases where options such asAt.ordinal()are specified which naturally limit the number of results.booleancancellableSetting an injected callback to cancellable allows the injected callback to inject optional RETURN opcodes into the target method, the return behaviour can then be controlled from within the callback by interacting with the suppliedCallbackInfoobject.java.lang.StringconstraintsReturns constraints which must be validated for this injector to succeed.intexpectLikerequire()but only enabled if themixin.debug.countInjectionsoption is set to true and defaults to 1.java.lang.StringidThe identifier for this injector, can be retrieved via theCallbackInfo.getId()accessor.LocalCapturelocalsSpecifies the local variable capture behaviour for this injector.java.lang.String[]methodString representation of one or moretarget selectorswhich identify the target methods.intorderBy default almost all injectors for a target class apply their injections at the same time.booleanremapintrequireIn general, injectors are intended to "fail soft" in that a failure to locate the injection point in the target method is not considered an error condition.Slice[]sliceDesc[]targetLiteral representation of one or more@Descannotations which identify the target methods.
-
-
-
Element Detail
-
at
At[] at
Array ofAtannotations which describe theInjectionPoints in the target method. Allows one or more callbacks to be injected in the target method.- Returns:
- injection point specifiers for this injector
-
-
-
id
java.lang.String id
The identifier for this injector, can be retrieved via theCallbackInfo.getId()accessor. If not specified, the ID defaults to the target method name.- Returns:
- the injector id to use
- Default:
- ""
-
-
-
method
java.lang.String[] method
String representation of one or moretarget selectorswhich identify the target methods.- Returns:
- target method(s) for this injector
- Default:
- {}
-
-
-
cancellable
boolean cancellable
Setting an injected callback to cancellable allows the injected callback to inject optional RETURN opcodes into the target method, the return behaviour can then be controlled from within the callback by interacting with the suppliedCallbackInfoobject.- Returns:
- true if this injector should inject appropriate RETURN opcodes which allow it to be cancelled
- Default:
- false
-
-
-
locals
LocalCapture locals
Specifies the local variable capture behaviour for this injector.When capturing local variables in scope, the variables are appended to the callback invocation after the
CallbackInfoargument.Capturing local variables from the target scope requires careful planning because unlike other aspects of an injection (such as the target method name and signature), the local variable table is not safe from modification by other transformers which may be in use in the production environment. Even other injectors which target the same target method have the ability to modify the local variable table and thus it is in no way safe to assume that local variables in scope at development time will be so in production.
To provide some level of flexibility, especially where changes can be anticipated (for example a well-known mod makes changes which result in a particular structure for the local variable table) it is possible to provide overloads for the handler method which will become surrogate targets for the orphaned injector by annotating them with an
Surrogateannotation.You can improve the robustness of your local capture injection by only specifying locals up to the last variable you wish to use. For example if the target LVT contains <int, int, int, float, String> and you only need the float value, you can choose to omit the unused String and changes to the LVT beyond that point will not affect your injection.
It is also important to nominate the failure behaviour to follow when local capture fails and so all
LocalCapturebehaviours which specify a capture action imply a particular behaviour for handling failure. See the javadoc on theLocalCapturemembers for more details.Determining what local variables are available to you and in what order can be somewhat tricky, and so a simple mechanism for enumerating available locals is provided. By setting
localstoLocalCapture.PRINT, the injector writes the local capture state to STDERR instead of injecting the callback. Using the output thus obtained it is then a straightforward matter of altering the callback method signature to match the signature proposed by the Callback Injector.- Returns:
- the desired local capture behaviour for this injector
- Default:
- org.spongepowered.asm.mixin.injection.callback.LocalCapture.NO_CAPTURE
-
-
-
remap
boolean remap
By default, the annotation processor will attempt to locate an obfuscation mapping for allInjectmethods since it is anticipated that in general the target of aInjectannotation will be an obfuscated 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 necessary to suppress the compiler error 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
-
-
-
require
int require
In general, injectors are intended to "fail soft" in that a failure to locate the injection point in the target method is not considered an error condition. Another transformer may have changed the method structure or any number of reasons may cause an injection to fail. This also makes it possible to define several injections to achieve the same task given expected mutation of the target class and the injectors which fail are simply ignored.However, this behaviour is not always desirable. For example, if your application depends on a particular injection succeeding you may wish to detect the injection failure as an error condition. This argument is thus provided to allow you to stipulate a minimum number of successful injections for this callback handler. If the number of injections specified is not achieved then an
InjectionErroris thrown at application time. Use this option with care.- Returns:
- Minimum required number of injected callbacks, default specified by the containing config
- Default:
- -1
-
-
-
expect
int expect
Likerequire()but only enabled if themixin.debug.countInjectionsoption is set to true and defaults to 1. Use this option during debugging to perform simple checking of your injectors. Causes the injector to throw aInvalidInjectionExceptionif the expected number of injections is not realised.- Returns:
- Minimum number of expected callbacks, default 1
- Default:
- 1
-
-
-
allow
int allow
Injection points are in general expected to match every candidate instruction in the target method or slice, except in cases where options such asAt.ordinal()are specified which naturally limit the number of results.This option allows for sanity-checking to be performed on the results of an injection point by specifying a maximum allowed number of matches, similar to that afforded by
Group.max(). For example if your injection is expected to match 4 invocations of a target method, but instead matches 5, this can become a detectable tamper condition by setting this value to 4.Setting any value 1 or greater is allowed. Values less than 1 or less than
require()are ignored.require()supercedes this argument such that if allow is less than require the value of require is always used.Note that this option is not a limit on the query behaviour of this injection point. It is only a sanity check used to ensure that the number of matches is not too high
- Returns:
- Maximum allowed number of injections for this
- Default:
- -1
-
-
-
constraints
java.lang.String constraints
Returns constraints which must be validated for this injector to succeed. SeeConstraintParser.Constraintfor details of constraint formats.- Returns:
- Constraints for this annotation
- Default:
- ""
-
-
-
order
int order
By default almost all injectors for a target class apply their injections at the same time. In other words, if multiple mixins target the same class then injectors are applied in priority order (since the mixins themselves are merged in priority order, and injectors run in the order they were merged). The exception being redirect injectors, which apply in a later pass.The default order for injectors is 1000, and redirect injectors use 10000.
Specifying a value for order alters this default behaviour and causes the injector to inject either earlier or later than it normally would. For example specifying 900 will cause the injector to apply before others, while 1100 will apply later. Injectors with the same order will still apply in order of their mixin's priority.
- Returns:
- the application order for this injector, uses DEFAULT (1000) if not specified
- Default:
- 1000
-
-