====== インジェクション ======
===== 導入 =====
インジェクションを用いると、既存のメソッドの任意の場所にコードを挿入することができます。実例を見たい方は、このページ下部の [[ja:tutorial:mixin_injects#実例|実例]] を参照してください。以下はインジェクションのメソッドの基本のコードです:
@Inject(method = "メソッド記述子", at = @At("インジェクションポイント"))
private void injectMethod(METHOD ARGS, CallbackInfo info) {
}
[[https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference|Injection Point Reference]] に全てのインジェクションポイントがあります。以下のリストは主要なものです:
^ インジェクションポイント ^ 説明 ^
| HEAD | メソッドの最初 |
| RETURN | 全ての return 文の前 |
| TAIL | 最後の return 文の前 |
| INVOKE | メソッドが呼ばれたとき |
インジェクションポイントが文またはメンバを指すとき、''@At'' 内の ''target'' に目的の値を設定することができます。その際、 JVM バイトコード記述子として設定します。
Oracle は以下の [[https://docs.oracle.com/javase/specs/jvms/se14/html/jvms-4.html#jvms-4.3.2|フィールド記述子]] を定めています:
^ 記述子 ^ 型 ^ 説明 ^
| B | byte | 符号付きバイト |
| C | char | UTF-16 でエンコードされた、基本多言語面の Unicode コードポイント値 |
| D | double | 倍精度浮動小数点数 |
| F | float | 単精度浮動小数点数 |
| I | int | 符号付き整数 |
| J | long | 符号付き長整数 |
| S | short | 符号付き短整数 |
| Z | boolean | ''true'' または ''false'' |
| L//ClassName//; | 参照 | //ClassName// のインスタンス |
| [ | 参照 | 配列の 1 次元 |
メソッド記述子は、メソッド名、括弧で囲まれた引数の型、返り値の型によって構成されます。例えば、''Object m(int i, double[] d, Thread t)'' と定義されたメソッドの記述子は ''m(I[DLjava/lang/Thread;)Ljava/lang/Object;'' になります。
メソッドの返り値の型が ''void'' である場合、''V'' (Void 記述子型)を型として用います。''void foo(String bar)'' の記述子は ''foo(Ljava/lang/String;)V'' です。
ジェネリックは実行時に存在しないため、それらの型は省略されます。''Pair>'' の記述子は ''Lcom/mojang/datafixers/util/Pair'' です。
インジェクションのメソッドの返り値の型は常に ''void'' です。一方、メソッド名やアクセス修飾子は任意であるため、そのインジェクションの内容に適するようにしてください。また、インジェクションのメソッドの引数が目的のメソッドの引数と同じになるようにして、最後に ''CallbackInfo'' 型の引数が 1 つ渡されるようにしてください。目的のメソッドの返り値の型が ''(T)'' である場合は、''CallbackInfo'' 型の代わりに ''CallbackInfoReturnable'' 型を使用してください。
=== インジェクションのメソッドからの return とキャンセル ===
インジェクションのメソッド内で目的のメソッドの処理をキャンセルしたり、早期 return したりしたい場合は、''CallbackInfo#cancel'' または ''CallbackInfoReturnable#setReturnValue(T)'' を使用してください。その際、''@Inject'' 内で ''cancellable'' に ''true'' を設定することと、''setReturnValue'' を呼んだあとに ''cancel'' を呼ばないようにすることに注意してください。
@Inject(method = "...", at = @At("..."), cancellable = true)
=== コンストラクタへのインジェクション ===
コンストラクタにインジェクションを行う場合は、''()V'' が目的のメソッド記述子となるようにします。その際、''()'' 内にコンストラクタの引数の記述子を設定してください。公式にサポートされているインジェクションポイントの値は ''TAIL'' または ''RETURN'' のみです。いくつかのクラスは '''' と異なる ''init'' と名付けられたメソッドを持つため、混乱しないように注意してください。
static なコンストラクタにインジェクションを行う場合は、メソッド名が '''' になるようにしてください。
===== 実例 =====
以下のコードは ''TitleScreen#init'' メソッドの先頭で出力を行う例です。(''init'' はメソッド名であり、コンストラクタではありません。)
@Mixin(TitleScreen.class)
public class ExampleMixin {
@Inject(at = @At("HEAD"), method = "init()V")
private void init(CallbackInfo info) {
System.out.println("This line is printed by an example mod mixin!"); // この行は example mod の mixin によって出力されます!
}
}
この例に関して更なる情報が欲しい方は、[[https://github.com/FabricMC/fabric-example-mod/blob/master/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java|Fabric Example Mod リポジトリ]] を参照してください。