From 7e10263c27ca4f88313d92564b2193264aaa411a Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:51:36 +0000 Subject: [PATCH 1/2] issues/256 - Nested option with map deserialization fix. --- .../sdk/model/clvalue/cltype/CLTypeMap.java | 15 ++++++++++++++ .../sdk/model/clvalue/CLValueTests.java | 20 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/main/java/com/casper/sdk/model/clvalue/cltype/CLTypeMap.java b/src/main/java/com/casper/sdk/model/clvalue/cltype/CLTypeMap.java index 276445161..2a31e34a2 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/cltype/CLTypeMap.java +++ b/src/main/java/com/casper/sdk/model/clvalue/cltype/CLTypeMap.java @@ -12,6 +12,8 @@ import dev.oak3.sbs4j.exception.ValueDeserializationException; import lombok.*; +import java.util.List; + /** * CLType for {@link AbstractCLType#MAP} * @@ -53,6 +55,19 @@ public boolean isDeserializable() { } } + /** + * Allows generic setting of child types so we don't need specialized code for byte deserialization. + * + * @param childTypes the child types + */ + @Override + public void setChildTypes(final List childTypes) { + super.setChildTypes(childTypes); + if (childTypes.size() >= 2) { + setKeyValueTypes(new CLTypeMapEntryType(childTypes.get(0), childTypes.get(1))); + } + } + /** * Support class for {@link AbstractCLType#MAP} entry types * diff --git a/src/test/java/com/casper/sdk/model/clvalue/CLValueTests.java b/src/test/java/com/casper/sdk/model/clvalue/CLValueTests.java index eb19b52e2..ea198457f 100644 --- a/src/test/java/com/casper/sdk/model/clvalue/CLValueTests.java +++ b/src/test/java/com/casper/sdk/model/clvalue/CLValueTests.java @@ -364,4 +364,24 @@ void Ed25519PublicKeySerialization() throws Exception { assertThat(deserialized.getBytes(), is(clValuePublicKey.getBytes())); } + @Test + void nestedOptionWithMap() throws Exception { + + final Map map = new HashMap<>(); + map.put(new CLValueString("ONE"), new CLValueU32(2L)); + final CLValueMap innerMap = new CLValueMap(map); + final CLValueOption innerOption = new CLValueOption(Optional.of(innerMap)); + CLValueOption clValueOption = new CLValueOption(Optional.of(innerOption)); + + assertThat(clValueOption.getBytes(), is("010101000000030000004f4e4502000000")); + + final SerializerBuffer ser = new SerializerBuffer(); + clValueOption.serialize(ser, Target.BYTE); + + final byte[] bytes = ser.toByteArray(); + assertThat(bytes, is(Hex.decode("11000000010101000000030000004f4e45020000000d0d110a04"))); + + final CLValueOption deserialized = (CLValueOption) clValueOption.deserialize(new DeserializerBuffer(bytes), Target.BYTE); + assertThat(deserialized.getBytes(), is(clValueOption.getBytes())); + } } From 6be16cc6110c9bf33ab5864c7976ff92454bd353 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:27:29 +0000 Subject: [PATCH 2/2] issues/256 - Push up common code for child type setting into AbstractCLValueWithChildren. --- .../clvalue/AbstractCLValueWithChildren.java | 12 ++++++++++++ .../casper/sdk/model/clvalue/CLValueList.java | 10 +--------- .../casper/sdk/model/clvalue/CLValueMap.java | 18 +++--------------- .../sdk/model/clvalue/CLValueOption.java | 17 ++++------------- .../sdk/model/clvalue/CLValueTuple1.java | 10 +++------- .../sdk/model/clvalue/CLValueTuple2.java | 11 ++--------- .../sdk/model/clvalue/CLValueTuple3.java | 17 ++++------------- 7 files changed, 29 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/casper/sdk/model/clvalue/AbstractCLValueWithChildren.java b/src/main/java/com/casper/sdk/model/clvalue/AbstractCLValueWithChildren.java index 5cd53ae4a..82cac2402 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/AbstractCLValueWithChildren.java +++ b/src/main/java/com/casper/sdk/model/clvalue/AbstractCLValueWithChildren.java @@ -1,7 +1,9 @@ package com.casper.sdk.model.clvalue; import com.casper.sdk.annotation.ExcludeFromJacocoGeneratedReport; +import com.casper.sdk.model.clvalue.cltype.AbstractCLType; import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; +import com.casper.sdk.model.clvalue.cltype.CLTypeByteArray; import com.fasterxml.jackson.annotation.JsonSetter; import dev.oak3.sbs4j.DeserializerBuffer; import dev.oak3.sbs4j.exception.ValueDeserializationException; @@ -33,6 +35,16 @@ protected void childTypesSet() { } } + protected void populateChildTypesFromParent(final AbstractCLValue child, final AbstractCLType type) { + if (type instanceof AbstractCLTypeWithChildren) { + if (child.getClType() instanceof AbstractCLTypeWithChildren) { + ((AbstractCLTypeWithChildren) child.getClType()).setChildTypes(((AbstractCLTypeWithChildren)type).getChildTypes()); + } else if (child instanceof CLValueByteArray) { + ((CLValueByteArray) child).setClType((CLTypeByteArray) ((AbstractCLTypeWithChildren)type).getChildTypes().get(0)); + } + } + } + /** * Sets the bytes and if the CLType is already set, fires bytes deserialization * diff --git a/src/main/java/com/casper/sdk/model/clvalue/CLValueList.java b/src/main/java/com/casper/sdk/model/clvalue/CLValueList.java index 8200d59da..02d613bb3 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/CLValueList.java +++ b/src/main/java/com/casper/sdk/model/clvalue/CLValueList.java @@ -1,9 +1,7 @@ package com.casper.sdk.model.clvalue; -import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; import com.casper.sdk.model.clvalue.cltype.CLTypeData; import com.casper.sdk.model.clvalue.cltype.CLTypeList; -import com.casper.sdk.model.clvalue.cltype.CLTypeMap; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; import dev.oak3.sbs4j.DeserializerBuffer; @@ -78,13 +76,7 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception { final List> list = new ArrayList<>(); for (int i = 0; i < length.getValue(); i++) { final AbstractCLValue child = CLTypeData.createCLValueFromCLTypeData(childrenType); - if (child.getClType() instanceof CLTypeMap) { - ((CLTypeMap) child.getClType()) - .setKeyValueTypes(((CLTypeMap) clType.getListType()).getKeyValueTypes()); - } else if (child.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getListType()).getChildTypes()); - } + populateChildTypesFromParent(child, clType.getListType()); child.deserializeCustom(deser); list.add(child); } diff --git a/src/main/java/com/casper/sdk/model/clvalue/CLValueMap.java b/src/main/java/com/casper/sdk/model/clvalue/CLValueMap.java index e5d81c638..206cb092f 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/CLValueMap.java +++ b/src/main/java/com/casper/sdk/model/clvalue/CLValueMap.java @@ -1,6 +1,5 @@ package com.casper.sdk.model.clvalue; -import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; import com.casper.sdk.model.clvalue.cltype.CLTypeData; import com.casper.sdk.model.clvalue.cltype.CLTypeMap; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -85,23 +84,12 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception { for (int i = 0; i < mapLength.getValue(); i++) { final AbstractCLValue key = CLTypeData.createCLValueFromCLTypeData(keyType); - if (key.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) key.getClType()) - .setChildTypes( - ((AbstractCLTypeWithChildren) clType.getKeyValueTypes().getKeyType()).getChildTypes()); - } + // It's very unlikely we have a key that is complex type but adding support + populateChildTypesFromParent(key, clType.getKeyValueTypes().getKeyType()); key.deserializeCustom(deser); final AbstractCLValue val = CLTypeData.createCLValueFromCLTypeData(valType); - - if (val.getClType() instanceof CLTypeMap) { - ((CLTypeMap) val.getClType()) - .setKeyValueTypes(((CLTypeMap) clType.getKeyValueTypes().getValueType()).getKeyValueTypes()); - } else if (val.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) val.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getKeyValueTypes().getValueType()) - .getChildTypes()); - } + populateChildTypesFromParent(val, clType.getKeyValueTypes().getValueType()); val.deserializeCustom(deser); map.put(key, val); diff --git a/src/main/java/com/casper/sdk/model/clvalue/CLValueOption.java b/src/main/java/com/casper/sdk/model/clvalue/CLValueOption.java index ded0ed933..4145524df 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/CLValueOption.java +++ b/src/main/java/com/casper/sdk/model/clvalue/CLValueOption.java @@ -1,6 +1,8 @@ package com.casper.sdk.model.clvalue; -import com.casper.sdk.model.clvalue.cltype.*; +import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; +import com.casper.sdk.model.clvalue.cltype.CLTypeData; +import com.casper.sdk.model.clvalue.cltype.CLTypeOption; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; import dev.oak3.sbs4j.DeserializerBuffer; @@ -70,19 +72,8 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception { isPresent.deserializeCustom(deser); final CLTypeData childTypeData = clType.getOptionType().getClTypeData(); - final AbstractCLValue child = CLTypeData.createCLValueFromCLTypeData(childTypeData); - - if (child.getClType() instanceof CLTypeList) { - ((CLTypeList) child.getClType()) - .setListType(((CLTypeList) clType.getOptionType()).getListType()); - } else if (child.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getOptionType()).getChildTypes()); - } else if (child instanceof CLValueByteArray) { - // Byte arrays require their length to be set to correctly deserialize - ((CLValueByteArray) child).setClType((CLTypeByteArray) clType.getOptionType()); - } + populateChildTypesFromParent(child, clType.getOptionType()); if (Boolean.TRUE.equals(isPresent.getValue())) { child.deserializeCustom(deser); diff --git a/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple1.java b/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple1.java index 3d7be7f85..ed8846c55 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple1.java +++ b/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple1.java @@ -1,6 +1,5 @@ package com.casper.sdk.model.clvalue; -import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; import com.casper.sdk.model.clvalue.cltype.CLTypeData; import com.casper.sdk.model.clvalue.cltype.CLTypeTuple1; import com.fasterxml.jackson.annotation.JsonProperty; @@ -57,13 +56,10 @@ protected void serializeValue(final SerializerBuffer ser) throws ValueSerializat @Override public void deserializeCustom(final DeserializerBuffer deser) throws Exception { - CLTypeData childTypeData1 = clType.getChildClTypeData(0); + final CLTypeData childTypeData1 = clType.getChildClTypeData(0); - AbstractCLValue child1 = CLTypeData.createCLValueFromCLTypeData(childTypeData1); - if (child1.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child1.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getChildTypes().get(0)).getChildTypes()); - } + final AbstractCLValue child1 = CLTypeData.createCLValueFromCLTypeData(childTypeData1); + populateChildTypesFromParent(child1, clType.getChildTypes().get(0)); child1.deserializeCustom(deser); setValue(new Unit<>(child1)); diff --git a/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple2.java b/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple2.java index 1fcf0fd8f..7264dbd88 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple2.java +++ b/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple2.java @@ -1,6 +1,5 @@ package com.casper.sdk.model.clvalue; -import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; import com.casper.sdk.model.clvalue.cltype.CLTypeData; import com.casper.sdk.model.clvalue.cltype.CLTypeTuple2; import com.fasterxml.jackson.annotation.JsonProperty; @@ -64,17 +63,11 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception { final CLTypeData childTypeData2 = clType.getChildClTypeData(1); final AbstractCLValue child1 = CLTypeData.createCLValueFromCLTypeData(childTypeData1); - if (child1.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child1.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getChildTypes().get(0)).getChildTypes()); - } + populateChildTypesFromParent(child1, clType.getChildTypes().get(0)); child1.deserializeCustom(deser); final AbstractCLValue child2 = CLTypeData.createCLValueFromCLTypeData(childTypeData2); - if (child2.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child2.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getChildTypes().get(1)).getChildTypes()); - } + populateChildTypesFromParent(child2, clType.getChildTypes().get(1)); child2.deserializeCustom(deser); setValue(new Pair<>(child1, child2)); diff --git a/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple3.java b/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple3.java index e48e1674d..a798a6b64 100644 --- a/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple3.java +++ b/src/main/java/com/casper/sdk/model/clvalue/CLValueTuple3.java @@ -1,6 +1,5 @@ package com.casper.sdk.model.clvalue; -import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren; import com.casper.sdk.model.clvalue.cltype.CLTypeData; import com.casper.sdk.model.clvalue.cltype.CLTypeTuple3; import com.fasterxml.jackson.annotation.JsonProperty; @@ -65,29 +64,21 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception { final CLTypeData childTypeData3 = clType.getChildClTypeData(2); final AbstractCLValue child1 = CLTypeData.createCLValueFromCLTypeData(childTypeData1); - if (child1.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child1.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getChildTypes().get(0)).getChildTypes()); - } + populateChildTypesFromParent(child1, clType.getChildTypes().get(0)); child1.deserializeCustom(deser); final AbstractCLValue child2 = CLTypeData.createCLValueFromCLTypeData(childTypeData2); - if (child2.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child2.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getChildTypes().get(1)).getChildTypes()); - } + populateChildTypesFromParent(child2, clType.getChildTypes().get(1)); child2.deserializeCustom(deser); final AbstractCLValue child3 = CLTypeData.createCLValueFromCLTypeData(childTypeData3); - if (child3.getClType() instanceof AbstractCLTypeWithChildren) { - ((AbstractCLTypeWithChildren) child3.getClType()) - .setChildTypes(((AbstractCLTypeWithChildren) clType.getChildTypes().get(2)).getChildTypes()); - } + populateChildTypesFromParent(child3, clType.getChildTypes().get(2)); child3.deserializeCustom(deser); setValue(new Triplet<>(child1, child2, child3)); } + @Override protected void setChildTypes(final Triplet, ? extends AbstractCLValue, ? extends AbstractCLValue> value) { if (value.getValue0() != null && value.getValue1() != null && value.getValue2() != null) {