Injecting - Revxrsal/Tuna-Bytes GitHub Wiki
Injecting is a powerful feature that is intended to solve the drawbacks of overwriting methods.
Sometimes, overwriting a method is an overkill, when we would like to only add a small line of code, or add an additional constraint to the method, without having to overwrite everything.
Another important use case is having multiple injects on the same method, without one of them dismissing the other.
Injection can happen at 5 places:
- Beginning of a method: Just before anything happens in the method
- Very end of the method: At the very end of the method (note: the end! not before each
return
statement) - Before each
return
statement: Before the method returns any result. This also includes any stop-all-the-execution point in the method. - Before a certain line number: In case of knowing the line number from the source code, we can inject code before that line
- After a certain line number: In case of knowing the line number from the source code, we can inject code right after that line
In the last 2 cases, where a line number is to be specified, the lineNumber
property has to be set in the @Inject
annotation.
Let's say we have a fluffy, simple Animal
class:
public class Animal {
public String getSound(String animal) {
switch (animal) {
case "Wolf":
return "Bark";
case "Cat":
return "Meow";
case "Cow":
return "MOO";
default:
return "*makes human sound*";
}
}
}
Injection is done using the @Inject
annotation:
import io.tunabytes.Mirror;
import io.tunabytes.Inject;
import io.tunabytes.Inject.At;
import io.tunabytes.Mixin;
@Mixin(Animal.class)
public class AnimalMixin {
@Inject(method = "getSound", at = At.BEFORE_EACH_RETURN)
public void hearSomething() {
System.out.println("I think I heard something");
}
}
import io.tunabytes.bytecode.MixinsBootstrap;
public final class AnimalTest {
public static void main(String[] args) {
MixinsBootstrap.init();
Animal animal = new Animal();
System.out.println(animal.getSound("Cat"));
System.out.println(animal.getSound("human thing"));
}
}
Output:
I think I heard something
Meow
I think I heard something
*makes human noise*
Important note: Injected code will be directly translated into the targeted method, and not wrapped into an external method invocation. For example, any return
in the injected code will translate into an actual return
in the target method.
Another note: When injecting, it is quite possible that you may need to reference to the class fields or other methods. In that case, take a look at mirroring.