From 7f8f55d90d91741b6ebbc62553618dd7b2161199 Mon Sep 17 00:00:00 2001 From: Peter Froud Date: Fri, 3 Jun 2022 19:24:19 -0700 Subject: [PATCH 1/2] Keep reference to type of SimpleNode value --- .../mingun/kaitai/struct/tree/ChunkNode.java | 4 ++-- .../mingun/kaitai/struct/tree/ListNode.java | 23 ++++++++++++++++--- .../mingun/kaitai/struct/tree/SimpleNode.java | 8 ++++++- .../mingun/kaitai/struct/tree/StructNode.java | 2 +- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java index b6d1838..c9e4395 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java @@ -77,9 +77,9 @@ public abstract class ChunkNode extends ValueNode { * @throws ReflectiveOperationException If {@code value} is {@link KaitaiStruct} * and it was compiled without debug info (which includes position information) */ - protected ChunkNode create(String name, Object value, long offset, long start, long end) throws ReflectiveOperationException { + protected ChunkNode create(String name, Object value, Class classOfValue, long offset, long start, long end) throws ReflectiveOperationException { return value instanceof KaitaiStruct ? new StructNode(name, (KaitaiStruct)value, this, offset, start, end) - : new SimpleNode(name, value, this, offset, start, end); + : new SimpleNode(name, value, classOfValue, this, offset, start, end); } } diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java index e160668..7fe4804 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java @@ -23,11 +23,14 @@ */ package ru.mingun.kaitai.struct.tree; +import javax.swing.tree.TreeNode; import java.util.ArrayList; -import static java.util.Collections.enumeration; import java.util.Enumeration; import java.util.List; -import javax.swing.tree.TreeNode; +import java.util.Objects; +import java.util.Optional; + +import static java.util.Collections.enumeration; /** * Node, that represents a repeated data in struct definition. An each repeated value @@ -91,7 +94,21 @@ private List init() { try { final int s = arrStart.get(index); final int e = arrEnd.get(index); - children.add(create("[" + index + ']', obj, 0, s, e)); + + /* + We cannot access the generic type of the List at runtime due to + type erasure. Instead, look for a non-null element in the List, + which will tell us the type of the whole list. + */ + final Class valueClass; + final Optional nonNullElement = value.stream().filter(Objects::nonNull).findAny(); + if (nonNullElement.isPresent()) { + valueClass = nonNullElement.get().getClass(); + } else { + valueClass = null; + } + + children.add(create("[" + index + ']', obj, valueClass, 0, s, e)); ++index; } catch (ReflectiveOperationException ex) { throw new UnsupportedOperationException("Can't get list value at index " + index, ex); diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java index 30c6939..6dbb97a 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java @@ -37,14 +37,20 @@ public class SimpleNode extends ChunkNode { /** Parsed value of non-constructed type. */ private final Object value; - SimpleNode(String name, Object value, ChunkNode parent, long offset, long start, long end) { + /** Replace value.getClass() when value==null. */ + private final Class classOfValue; + + SimpleNode(String name, Object value, Class valueClass, ChunkNode parent, long offset, long start, long end) { super(name, parent, offset, start, end); this.value = value; + this.classOfValue = valueClass; } @Override public Object getValue() { return value; } + public Class getClassOfValue() { return classOfValue; } + // @Override public ChunkNode getChildAt(int childIndex) { diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java index 918ce80..86205c7 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java @@ -162,7 +162,7 @@ private ChunkNode create(Method getter) throws ReflectiveOperationException { final List se = arrEnd.get(name); return new ListNode(name, (List)field, this, offset, s, e, sa, se); } - return create(name, field, start, s, e); + return create(name, field, getter.getReturnType(), start, s, e); } private ArrayList init() { From 8dd6d8ab38f36fa32b001ce9e1914b503329b641 Mon Sep 17 00:00:00 2001 From: Peter Froud Date: Mon, 6 Jun 2022 17:58:17 -0700 Subject: [PATCH 2/2] Find List generic type from getter method --- .../mingun/kaitai/struct/tree/ChunkNode.java | 4 ++-- .../mingun/kaitai/struct/tree/ListNode.java | 23 +++++-------------- .../mingun/kaitai/struct/tree/SimpleNode.java | 8 +++---- .../mingun/kaitai/struct/tree/StructNode.java | 8 ++++++- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java index c9e4395..ee37f85 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/ChunkNode.java @@ -77,9 +77,9 @@ public abstract class ChunkNode extends ValueNode { * @throws ReflectiveOperationException If {@code value} is {@link KaitaiStruct} * and it was compiled without debug info (which includes position information) */ - protected ChunkNode create(String name, Object value, Class classOfValue, long offset, long start, long end) throws ReflectiveOperationException { + protected ChunkNode create(String name, Object value, Class valueClass, long offset, long start, long end) throws ReflectiveOperationException { return value instanceof KaitaiStruct ? new StructNode(name, (KaitaiStruct)value, this, offset, start, end) - : new SimpleNode(name, value, classOfValue, this, offset, start, end); + : new SimpleNode(name, value, valueClass, this, offset, start, end); } } diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java index 7fe4804..5bbd8c8 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/ListNode.java @@ -27,8 +27,6 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import java.util.Objects; -import java.util.Optional; import static java.util.Collections.enumeration; @@ -40,6 +38,10 @@ */ public class ListNode extends ChunkNode { private final List value; + + /** The parameter type of value. */ + private final Class valueClass; + /** Lazy populated list of child nodes. */ private List children; /** Start positions in root stream of each value object in {@link #value}. */ @@ -47,13 +49,14 @@ public class ListNode extends ChunkNode { /** Endo positions in root stream of each value object in {@link #value} (exclusive). */ private final List arrEnd; - ListNode(String name, List value, StructNode parent, + ListNode(String name, List value, Class valueClass, StructNode parent, long offset, long start, long end, List arrStart, List arrEnd ) { super(name, parent, offset, start, end); this.value = value; + this.valueClass = valueClass; this.arrStart = arrStart; this.arrEnd = arrEnd; } @@ -94,20 +97,6 @@ private List init() { try { final int s = arrStart.get(index); final int e = arrEnd.get(index); - - /* - We cannot access the generic type of the List at runtime due to - type erasure. Instead, look for a non-null element in the List, - which will tell us the type of the whole list. - */ - final Class valueClass; - final Optional nonNullElement = value.stream().filter(Objects::nonNull).findAny(); - if (nonNullElement.isPresent()) { - valueClass = nonNullElement.get().getClass(); - } else { - valueClass = null; - } - children.add(create("[" + index + ']', obj, valueClass, 0, s, e)); ++index; } catch (ReflectiveOperationException ex) { diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java index 6dbb97a..23932ca 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/SimpleNode.java @@ -37,19 +37,19 @@ public class SimpleNode extends ChunkNode { /** Parsed value of non-constructed type. */ private final Object value; - /** Replace value.getClass() when value==null. */ - private final Class classOfValue; + /** Static type of value, to identify the type when value is null. */ + private final Class valueClass; SimpleNode(String name, Object value, Class valueClass, ChunkNode parent, long offset, long start, long end) { super(name, parent, offset, start, end); this.value = value; - this.classOfValue = valueClass; + this.valueClass = valueClass; } @Override public Object getValue() { return value; } - public Class getClassOfValue() { return classOfValue; } + public Class getValueClass() { return valueClass; } // @Override diff --git a/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java b/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java index 86205c7..e330cfb 100644 --- a/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java +++ b/src/main/java/ru/mingun/kaitai/struct/tree/StructNode.java @@ -26,6 +26,8 @@ import io.kaitai.struct.KaitaiStruct; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import static java.util.Collections.enumeration; @@ -160,7 +162,11 @@ private ChunkNode create(Method getter) throws ReflectiveOperationException { if (List.class.isAssignableFrom(getter.getReturnType())) { final List sa = arrStart.get(name); final List se = arrEnd.get(name); - return new ListNode(name, (List)field, this, offset, s, e, sa, se); + + final ParameterizedType returnType = (ParameterizedType) getter.getGenericReturnType(); + final Type typeArgument = returnType.getActualTypeArguments()[0]; + + return new ListNode(name, (List) field, (Class) typeArgument, this, offset, s, e, sa, se); } return create(name, field, getter.getReturnType(), start, s, e); }