Mirroring - Revxrsal/Tuna-Bytes GitHub Wiki

Mirroring is a very powerful and important feature in mixins. It allows you to reference to the underlying class's fields and methods directly from inside your Mixins class.

Let's say we have this Car class:

public class Car {

    private final long number;
    private final String model;

    public Car(long number, String model) {
        this.number = number;
        this.model = model;
    }

    public void printInformation() {
        System.out.println("Boop boop");
    }

    public String getFullCarInfo() {
        return model + " - " + number;
    }
}

Since printInformation() doesn't really print anything useful, we would like to overwrite this and employ all the fields and methods in the Car class.

We will create a CarMixin class for this:

import io.tunabytes.Mirror;
import io.tunabytes.Mixin;
import io.tunabytes.Overwrite;

@Mixin(Car.class)
public abstract class CarMixin {

    @Mirror private String model;
    @Mirror private long number;

    @Overwrite
    public void printInformation() {
        System.out.println("Car model: " + model);
        System.out.println("Car number: " + number);
        System.out.println("Full car name: " + getFullCarInfo());
    }

    @Mirror public abstract String getFullCarInfo();

}

As we can see, model in the mixin class refers to the underlying model field. Similarly, invoking getFullCarInfo() is the same as calling the actual getFullCarInfo()

To verify this, let's run a quick test:

import io.tunabytes.bytecode.MixinsBootstrap;

public class CarTest {

    public static void main(String[] args) {
        MixinsBootstrap.init();
        Car car = new Car(2920031, "2020 Ford Raptor");
        car.printInformation();
    }
}

Output:

Car model: 2020 Ford Raptor
Car number: 2920031
Full car name: 2020 Ford Raptor - 2920031

For more information on mirroring, check the documentation at Mirror.java.