Quirks & Featuresstable
3 min read time

Documentation

Native Java

Working with java types for Java API's

jvminterop

Working with interfaces and abstract classes

While working against a Java API in PixelScript, you may encounter Java interfaces and abstract classes that you need to implement in order to use certain features. A good example of this is when working with ProtocolLib, where you need to extend the PacketAdapter abstract class to create a packet listener.

When you should to this

extending Java classes and interfaces should only be done when it's absolutely necessary that a a project in Java land holds a pointer to JS code. This is entirely separate rom JavaScript classes.

How to extend an abstract class

For this example we'll be looking at the ProtocolLib PacketAdapter. You can use the Java.extend function to create a new class that extends the abstract class.

Below is a simple example that demonstrates how to extend the PacketAdapter class and implement the required methods.

const ProtocolLibrary = Script.loadClass('com.comphenix.protocol.ProtocolLibrary'); const PacketAdapter = Script.loadClass('com.comphenix.protocol.events.PacketAdapter'); const PacketEvent = Script.loadClass('com.comphenix.protocol.events.PacketEvent'); const ListenerPriority = Script.loadClass('com.comphenix.protocol.events.ListenerPriority'); const PacketType = Script.loadClass('com.comphenix.protocol.PacketType'); // Create a new class that extends PacketAdapter const MyPacketAdapter = Java.extend(PacketAdapter, { onPacketReceiving: function(event) { const packet = event.getPacket(); const player = event.getPlayer(); console.log("Swing: " + player.getName()); } }); // Register the packet listener like normal, we now hold a reference to a JS object const protocolManager = ProtocolLibrary.getProtocolManager(); const listener = new MyPacketAdapter(Bukkit.getPluginManager().getPlugin("PixelScript"), ListenerPriority.MONITOR, [PacketType.Play.Client.ARM_ANIMATION]); protocolManager.addPacketListener(listener);

How to implement an interface

Implementing an interface can done by calling it as a constructor, and doesn't need special type gymnastics, you don't even need to define them most of the time!

Simple functional interfaces can be inlined normally, for example, a java interface that looks like this

@FunctionalInterface public interface MyFunctionalInterface { String execute(String message); }

can be implemented like this:

MyClass.someFunction((message) => { return "Hello, " + message; });

but there are cases where you may need to define multiple methods, or non-functional interfaces.

To demonstrate, we'll be using this simple interface:

public interface MyInterface { void doSomething(); int calculate(int a, int b); }

You can implement it like this:

const MyInterface = Script.loadClass('com.example.MyInterface'); // and then implement it const myImplementation = new MyInterface({ doSomething: function() { console.log("Doing something!"); }, calculate: function(a, b) { return a + b; } });

This MyInterface variable can then be passed back to your Java method, which will receive a generated class on the other end. No need to use Java.extend here!

Documentation in early stages. Not meant for public consumption.