Java codegen is gated by the java feature.
cargo run --features "java" -- --output-format java <IN> --output-dir <OUT> --java-package <PACKAGE>For example, cargo run --features "java" -- --output-format java protocol.pdl --output-dir ./target --java-package a.b will generate Java code as ./target/a/b/*.java. Each of these files will declare package a.b;.
- Optional fields
- element_size fields
- Custom fields
- Checksum declarations
- Test declarations
- Constraints on >1st order ancestors
Packets come with a builder, with the type of each field being the smallest Java integral type that fits the declared field width, or boolean if the field is 1 bit wide. Packet classes have a static <NAME> fromBytes(byte[]) and an instance byte[] toBytes(). Packet classes override hashCode, equals, and toString as expected.
packet MyPacket {
a: 8,
b: 16,
}
MyPacket packet1 = new MyPacket.Builder().setA((byte) 1).setB((short) 2).build();
MyPacket packet2 = MyPacket.fromBytes(new byte[] {1, 0, 2});
assert packet1.equals(packet2);Packet inheritance maps to Java inheritance. Each parent generates an abstract class with a static <PARENT_NAME> fromBytes(byte[]) that constructs an instance of one of its children. Packets with a _payload_ generate a concrete "fallback" child (Unknown<PARENT_NAME>) with a raw byte[] payload member. An instance of the fallback child is constructed if a concrete child can't be determined based on constraint values or child size. Packets with a _body_ throw an exception instead of constructing a fallback.
packet Parent {
a: 8,
_payload_,
}
packet Child : Parent(a = 1) {
b: 16,
}
switch (Parent.fromBytes(bytes)) {
case Child c -> System.out.println(c);
case UnknownParent other -> System.out.println(other);
}Child packet1 = new Child.Builder().setB((short) 1).build();
UnknownParent packet2 = new UnknownParent.Builder().setA((byte) 2).setPayload(new byte[] {3, 4}).build();
assert (packet1 instanceof Parent) && (packet2 instanceof Parent);Enums and their tags also map to a Java class hierarchy. Each enum generates an abstract class with a static <ENUM_NAME> from<T>(<T>) and instance <T> to<T>() where <T> is the smallest integral Java type that fits the enum's width. The enum has an inner subclass for each tag. Single-valued tags have singletons that shadow their class definitions while range and default tags have a constructor. Enum classes override hashCode, equals, and toString as expected.
enum MyEnum : 7 {
A = 1,
B = 2,
C = 3,
Other = ..
}
MyEnum a = MyEnum.A;
MyEnum other = MyEnum.Other((byte) 4);
assert MyEnum.fromByte((byte) 2).equals(MyEnum.B);enum NestedEnum : 3 {
A = 0,
B = 1..6 {
X = 1,
Y = 2,
},
}
switch (NestedEnum.fromByte(val)) {
case NestedEnum.A a -> {
System.out.println(a);
}
case NestedEnum.B b -> {
switch (b) {
case NestedEnum.B.X x -> {
System.out.println(x);
}
case NestedEnum.B.Y y -> {
System.out.println(y);
}
}
}
}