Skip to content

Commit fb76b5d

Browse files
committed
Generate enums as interface + enum + class for unknown values
The new generated enum is represented as an interface with two nested classes: - enum class Known with the list of known enumeration values - class Unknown which represents any not-known value The enums `enum` would be generated as: ```java interface Enum extends IKaitaiEnum { public static class Unknown extends IKaitaiEnum.Unknown implements Enum { private Unknown(long id) { super(id); } } public enum Known implements Enum { Variant1(1), Variant2(2), Variant(3); private final long id; static HashMap<Long, Enum> variants = new HashMap<>(3); static { for (final Known e : Known.values()) { variants.put(e.id, e); } } private Known(long id) { this.id = id; } @OverRide public long id() { return this.id; } } public static Enum byId(final long id) { return Known.variants.computeIfAbsent(id, _id -> new Unknown(id)); } } ``` Unfortunately, it is not possible to generate enum what will implement nested interface due to cyclic reference. If that would be possible, we would be protected against name clashes. In the current implementation the names Known and Unknown can clash with enum name itself
1 parent d105f21 commit fb76b5d

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,15 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
690690
val enumClass = type2class(enumName)
691691

692692
out.puts
693-
out.puts(s"public enum $enumClass {")
693+
out.puts(s"public interface $enumClass implements IKaitaiEnum {")
694+
out.inc
695+
out.puts(s"public static class Unknown extends IKaitaiEnum.Unknown implements $enumClass {")
696+
out.inc
697+
out.puts("Unknown(long id) { super(id); }")
698+
out.dec
699+
out.puts("}")
700+
out.puts
701+
out.puts(s"public enum Known implements $enumClass {")
694702
out.inc
695703

696704
if (enumColl.size > 1) {
@@ -705,23 +713,37 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
705713

706714
out.puts
707715
out.puts("private final long id;")
708-
out.puts(s"$enumClass(long id) { this.id = id; }")
709-
out.puts("public long id() { return id; }")
710-
out.puts(s"private static final Map<Long, $enumClass> byId = new HashMap<Long, $enumClass>(${enumColl.size});")
716+
out.puts(s"static final HashMap<Long, $enumClass> variants = new HashMap<>(${enumColl.size});")
711717
out.puts("static {")
712718
out.inc
713-
out.puts(s"for ($enumClass e : $enumClass.values())")
719+
out.puts(s"for ($enumClass e : $enumClass.values()) {")
714720
out.inc
715-
out.puts(s"byId.put(e.id(), e);")
721+
out.puts(s"variants.put(e.id, e);")
722+
out.dec
723+
out.puts("}")
724+
out.dec
725+
out.puts("}")
726+
out.puts
727+
out.puts("private Known(long id) { this.id = id; }")
728+
out.puts
729+
out.puts("@Override")
730+
out.puts("public long id() { return id; }")
731+
out.puts
732+
out.puts("@Override");
733+
out.puts(s"public String toString() { return \"${enumClass}(\" + this.id + \")>\"; }");
716734
out.dec
735+
out.puts("}")
736+
out.puts
737+
out.puts(s"public static $enumClass byId(final long id) {")
738+
out.inc
739+
out.puts("return Known.variants.computeIfAbsent(id, _id -> new Unknown(id));")
717740
out.dec
718741
out.puts("}")
719-
out.puts(s"public static $enumClass byId(long id) { return byId.get(id); }")
720742
out.dec
721743
out.puts("}")
722744

723-
importList.add("java.util.Map")
724745
importList.add("java.util.HashMap")
746+
importList.add("io.kaitai.struct.IKaitaiEnum")
725747
}
726748

727749
override def debugClassSequence(seq: List[AttrSpec]) = {

shared/src/main/scala/io/kaitai/struct/translators/JavaTranslator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class JavaTranslator(provider: TypeProvider, importList: ImportList) extends Bas
6767
s"${JavaCompiler.publicMemberName(id)}()"
6868

6969
override def doEnumByLabel(enumTypeAbs: List[String], label: String): String =
70-
s"${enumClass(enumTypeAbs)}.${Utils.upperUnderscoreCase(label)}"
70+
s"${enumClass(enumTypeAbs)}.Known.${Utils.upperUnderscoreCase(label)}"
7171
override def doEnumById(enumTypeAbs: List[String], id: String): String =
7272
s"${enumClass(enumTypeAbs)}.byId($id)"
7373

0 commit comments

Comments
 (0)