Skip to content

Mixin

Mixinトリック

Mixinで継承する

対象クラスの継承・実装しているインターフェースをMixinクラスでも継承することで、スーパークラスのメソッドやフィールド等にアクセスすることができます。

コンストラクタを生成する必要がありますが、無視されるため実装して大丈夫です。

Info

対象が抽象クラスの場合、メソッドを実装する必要が出てくるので、Mixinクラスも抽象クラスにしましょう。

@Mixin(Example.class)
public abstract class ExampleMixin extends ExampleParent implements ExampleInterface {

    public ExampleMixin(...) {
        super(...);
    }
}

Mixinでオーバーライドする

Mixinクラスにあるメソッドやフィールドは基本的に対象クラスにマージされるため、そのままオーバーライドが可能です。

他Modが同じクラスで同じメソッドをオーバーライドした場合競合するため、あまりおすすめできません。

できれば #ソフトオーバーライド を使用してください。

public class ExampleParent {
    public void exampleMethod() {
        System.out.println("Super");
    }
}

public class Example extends ExampleParent {
}

@Mixin(Example.class)
public class ExampleMixin extends ExampleParent {
    @Override
    public void exampleMethod() {
        super.exampleMethod();
        System.out.println("Override");
    }
}

Mixinでインターフェースを実装する

Mixinクラスは対象クラスにマージされるため、独自インターフェースを実装することができます。

@Unique と組み合わせることで、クラスに任意のデータを付与しアクセスすることができます。

public interface MyInterface {
    void example$exampleMethod();
    String example$getExampleValue();
}

@Mixin(Example.class)
public class ExampleMixin implements MyInterface {
    @Unique
    private String example$exampleValue = "Hello World";

    @Unique
    @Override
    public void example$exampleMethod() {
        System.out.println("Mixin");
    }

    @Unique
    @Override
    public String example$getExampleValue() {
        return example$exampleValue;
    }
}

// 使用法
Example example = ...;
MyInterface myInterface = (MyInterface) example;

myInterface.example$exampleMethod();
System.out.println(myInterface.example$getExampleValue());

ソフトオーバーライド

Mixinメソッドを継承できるシステムを利用したものです。

インジェクションをオーバーライドし、特定のクラスでのインジェクションの動作を変更することができます。

Info

対象のクラスに存在しないメソッドをオーバーライドしたい場合、競合の可能性が高くなるため、定義クラスのメソッドをソフトオーバーライドして実装することが推奨されています。

詳しくは Mixin Inheritance を参照

@SoftOverride はなくても良いですが、有効か検証してくれるので書いておきましょう。

public class ExampleParent {
    protected void exampleMethod() {
        System.out.println("Original");
    }
}

public class Example extends ExampleParent {
}

@Mixin(ExampleParent.class)
public class ExampleParentMixin {

    @Inject(method = "exampleMethod", at = @At("HEAD"))
    protected void injectExampleMethod() {
    }

    @Unique
    protected void example$uniqueMethod() {
        System.out.println("Unique");
    }
}

@Mixin(Example.class)
public class ExampleMixin extends ExampleParentMixin {

    @Override
    @SoftOverride
    protected void injectExampleMethod() {
        System.out.println("Mixin");
    }

    @Override
    @SoftOverride
    protected void example$uniqueMethod() {
        System.out.println("Mixin");
    }
}

内部の仕組みについて

Java

  • ラムダ式は lambda$メソッド名$番号 のフォーマットの名前で関数に変換されます。

Mixin

  • Mixinクラスは対象のクラスにマージされる。
  • Mixinクラスは実行時にはロードできない(アクセッサーは可能)。