tutorial:interface_injection
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| tutorial:interface_injection [2022/03/08 21:06] – juuz | tutorial:interface_injection [2025/11/10 03:38] (current) – Add info on how to inject generic interfaces earthcomputer | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ======= Interface | + | ======= Interface |
| - | This is a new technique | + | ===== Overview ===== |
| - | More specifically, | + | |
| + | Interface injection | ||
| + | More specifically, | ||
| As result the target class will acquire all the methods of the interface, as if it always had them. | As result the target class will acquire all the methods of the interface, as if it always had them. | ||
| Interface injection is a compile time only feature, this means that a Mixin should also be used to implement the interface into the target class. | Interface injection is a compile time only feature, this means that a Mixin should also be used to implement the interface into the target class. | ||
| Line 8: | Line 10: | ||
| This is particularly useful for libraries, with this you can add new methods to existing classes and use them without the need of casting or reimplementing the interface every time. | This is particularly useful for libraries, with this you can add new methods to existing classes and use them without the need of casting or reimplementing the interface every time. | ||
| - | Let's explain better with an example: | + | Fabric API takes advantage of this technique. For example, '' |
| - | The scope of this example is to add the following method into FlowableFluid | + | ===== Example Goal ===== |
| - | This, normally, is not possible because | + | The scope of this example is to add the following method into ''< |
| + | This, normally, is not possible because | ||
| - | <code java [enable_line_numbers=" | + | <yarncode |
| - | Optional< | + | Optional< |
| - | </code> | + | </yarncode> |
| + | |||
| + | ===== Step 1: Create the Interface ===== | ||
| To add the method into the class, first of all you need to create an interface with it: | To add the method into the class, first of all you need to create an interface with it: | ||
| - | <code java [enable_line_numbers=" | + | <yarncode |
| package net.fabricmc.example; | package net.fabricmc.example; | ||
| public interface BucketEmptySoundGetter { | public interface BucketEmptySoundGetter { | ||
| - | // The methods in an injected interface MUST be default, | + | default Optional< |
| - | // otherwise code referencing them won't compile! | + | |
| - | default Optional< | + | |
| return Optional.empty(); | return Optional.empty(); | ||
| } | } | ||
| } | } | ||
| - | </code> | + | </yarncode> |
| - | Now you need to implement this interface | + | :!: The method body in the interface |
| - | <code java [enable_line_numbers=" | + | ℹ️ It's highly recommended to add a dollar-character or underscore character with the mod name as the prefix or suffix of the method name, in order to avoid method name conflict with other mods. |
| - | @Mixin(FlowableFluid.class) | + | |
| - | public | + | ===== Step 2: Implement the Interface with a Mixin ===== |
| + | |||
| + | Now you need to implement this interface into ''< | ||
| + | |||
| + | <yarncode | ||
| + | @Mixin(class_3609.class) | ||
| + | abstract | ||
| @Override | @Override | ||
| - | public Optional< | + | public Optional< |
| - | //This is how to get the default sound, copied from BucketItem class. | + | |
| - | return Optional.of(((FlowableFluid) (Object) this).isIn(FluidTags.LAVA) ? SoundEvents.ITEM_BUCKET_EMPTY_LAVA | + | |
| } | } | ||
| } | } | ||
| - | </code> | + | </yarncode> |
| - | Lastly you need to inject the interface into FlowableFluid. | + | ===== Step 3: Inject the Interface in '' |
| - | The following snippet can be added to your fabric.mod.json file to add one or more interfaces to the net/minecraft/ | + | |
| + | Lastly you need to inject the interface into ''< | ||
| + | The following snippet can be added to your '' | ||
| Note that all class names here must use the " | Note that all class names here must use the " | ||
| - | <code json [enable_line_numbers=" | + | < |
| { | { | ||
| " | " | ||
| Line 58: | Line 69: | ||
| </ | </ | ||
| - | Now you can use the new method: | + | :!: Sometimes, your interface injections may need to include the '' |
| - | <code java [enable_line_numbers=" | + | ==== Generic interfaces ==== |
| - | Optional<SoundEvent> | + | |
| + | If your interface has generics, you can specify them when you add the injected interface. For this, you need to add '' | ||
| + | |||
| + | ^ Description | ||
| + | | Class type | '' | ||
| + | | Array type | '' | ||
| + | | Primitive type (may appear as array elements) | '' | ||
| + | | Type variable | ||
| + | | Generic class type | '' | ||
| + | | Wildcard | ||
| + | | Extends wildcard bound | ''? | ||
| + | | Super wildcard bound | ''? | ||
| + | |||
| + | Here is a full example using generics: | ||
| + | <code json fabric.mod.json | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | } | ||
| + | } | ||
| </ | </ | ||
| + | which would generate the implementation: | ||
| + | < | ||
| + | public class class_3609 implements MyGenericInterface<? | ||
| + | // ... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Step 4: Using the Injected Method ===== | ||
| + | |||
| + | Now you can use the new method: | ||
| + | |||
| + | < | ||
| + | Optional< | ||
| + | </ | ||
| + | |||
| + | |||
| + | You could also override this method in classes extending ''< | ||
| + | |||
| - | You could also override this method in classes extending FlowableFluid to implement custom behaviours. | ||
tutorial/interface_injection.1646773611.txt.gz · Last modified: 2022/03/08 21:06 by juuz