Mixin Accessors 26.1.2
Learn how to access methods and fields using Mixin's Accessors and Invokers.
Mixins are typically used to modify existing code to produce and tweak behavior. However, Mixin also provides tools for accessing inaccessible fields and methods in the form of accessor mixins.
Class tweakers provides a similar tool in the form of access wideners, but Mixin's accessors do not require reloading Gradle, and can be applied to non-Minecraft targets.
Access widening is still necessary to override final methods or subclass final classes, or to reference private classes, as accessors can only target fields and methods.
Creating the Accessor Interface
Accessor mixins must always be an interface, and must only contain methods annotated with @Accessor or @Invoker. The interface must be annotated with @Mixin similarly to other mixin classes.
Accessor interfaces are conventionally named after their target class with Accessor suffixed, and placed in an accessor subpackage within your mixin package. Ie your.package.mixin.accessor
Field Accessors
Fields can be accessed using @Accessor-annotated getter and/or setter methods:
Getter/Setter Syntax:
Instance accessor methods should be prefixed by your mod's ID and a separator (conventionally $ or _) to ensure it does not clash with any other method.
java
@Accessor("<field name>")
FieldType example_mod$getFieldName();
@Accessor("<field name>")
void example_mod$setFieldName(FieldType value);1
2
3
4
5
2
3
4
5
Example:
java
@Mixin(Gui.class)
public interface GuiAccessor {
@Accessor("overlayMessageTime")
int example_mod$getOverlayMessageTime();
@Accessor("overlayMessageTime")
void example_mod$setOverlayMessageTime(int messageTime);
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Usage:
java
void exampleInstanceFieldAccessorUsage(Gui gui, int newMessageTime) {
int oldMessageTime = ((GuiAccessor) gui).example_mod$getOverlayMessageTime();
((GuiAccessor) gui).example_mod$setOverlayMessageTime(newMessageTime);
}1
2
3
4
5
2
3
4
5
Setting Final Fields
If the target field is final, annotate the accessor's setter method with @Mutable to remove the final flag during application:
java
@Mixin(Villager.class)
public interface VillagerAccessor {
@Accessor("FOOD_POINTS")
@Mutable
void example_mod$setItemFoodValues(Map<Item, Integer> items);
}1
2
3
4
5
6
2
3
4
5
6
Method Invokers
To call inaccessible methods or constructors, create a method matching the signature annotated with @Invoker:
Syntax:
Instance invoker methods should be prefixed by your mod's ID and a separator (conventionally $ or _) to ensure it does not clash with any other method.
Invoker methods are typically either named directly after the target method, or either invoke or call followed by the method name.
java
@Invoker("<method name>")
MethodReturnType modid$methodName(/* matching parameters */)1
2
2
Example:
java
@Mixin(Inventory.class)
public interface InventoryAccessor {
@Invoker("hasRemainingSpaceForItem")
boolean example_mod$hasRemainingSpaceForItem(ItemStack slotItemStack, ItemStack newItemStack);
}1
2
3
4
5
2
3
4
5
Usage:
java
void exampleInstanceMethodInvokerUsage(Inventory inventory, ItemStack slotItemStack, ItemStack newItemStack) {
if (((InventoryAccessor) inventory).example_mod$hasRemainingSpaceForItem(slotItemStack, newItemStack)) {
/* ... */
}
}1
2
3
4
5
2
3
4
5
Using Accessors for Final Classes
Because the Java compiler is stricter around final classes, it doesn't allow us to directly cast instances of it to an accessor interface.
To get around this, we only need to first cast to Object and then to the Accessor interface:
java
((TargetClassAccessor) (Object) targetClassInstance).example_mod$accessorMethod(/* ... */)1




