Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.rschmitt.dynamicobject;

import clojure.lang.PersistentHashMap;
import org.fressian.CachedObject;
import org.fressian.Writer;
import org.fressian.handlers.WriteHandler;
Expand Down Expand Up @@ -73,7 +74,14 @@ private TransformedMap(
Function<Object, Object> keysTransformation,
BiFunction<Object, Object, Object> valuesTransformation
) {
this.backingMap = backingMap;
if (backingMap.size() == 8) {
// If the backing map has 8 fields, Clojure Fressian deserializes it to a PersistentHashMap
// which means serializing -> deserializing -> serializing will yield a different value from the
// first serialization unless we serialize it as a PersistentHashMap here.
this.backingMap = (Map) PersistentHashMap.create(backingMap);
} else {
this.backingMap = backingMap;
}
this.keysTransformation = keysTransformation;
this.valuesTransformation = valuesTransformation;
}
Expand Down
36 changes: 36 additions & 0 deletions src/test/java/com/github/rschmitt/dynamicobject/FressianTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.rschmitt.dynamicobject;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -51,6 +52,30 @@ public void formatCompatibilityTest() throws Exception {
assertEquals(SAMPLE_VALUE, deserialized);
}

@Test
public void repeatedSerializationYieldsSameResultWith8Fields() throws Exception {
// This only surfaces with 8 fields, because Clojure Fressian deserializes maps with 8 keys
// as a PersistentHashMap, when it should deserialize it as a PersistentArrayMap.

DynamicObject.registerTag(DOWith8Fields.class, "doWith8Fields");
DOWith8Fields initialDO = DynamicObject.newInstance(DOWith8Fields.class)
.withField1("a")
.withField2("b")
.withField3("c")
.withField4("d")
.withField5("e")
.withField6("f")
.withField7("g")
.withField8("h");

byte[] serialized = DynamicObject.toFressianByteArray(initialDO);
DOWith8Fields deserialized = DynamicObject.fromFressianByteArray(serialized);

byte[] reserialized = DynamicObject.toFressianByteArray(deserialized);

assertArrayEquals(serialized, reserialized);
}

@Test
public void cachedKeys_canBeRoundTripped() throws Exception {
String cachedValue = "cached value";
Expand Down Expand Up @@ -93,4 +118,15 @@ public interface BinarySerialized extends DynamicObject<BinarySerialized> {
@Key(":null") BinarySerialized withNull(Object nil);
@Cached @Key(":cached") BinarySerialized withCached(String cached);
}

public interface DOWith8Fields extends DynamicObject<DOWith8Fields> {
@Key(":field1") DOWith8Fields withField1(String field1);
@Key(":field2") DOWith8Fields withField2(String field2);
@Key(":field3") DOWith8Fields withField3(String field3);
@Key(":field4") DOWith8Fields withField4(String field4);
@Key(":field5") DOWith8Fields withField5(String field5);
@Key(":field6") DOWith8Fields withField6(String field6);
@Key(":field7") DOWith8Fields withField7(String field7);
@Key(":field8") DOWith8Fields withField8(String field8);
}
}