#2059 Ordered map is unordered after serialization

endragor Thu 15 Nov 2012

map := [:] { ordered = true }
map["key0"] = "value0"
map["key1"] = "value1"

buf := Buf().writeObj(map).flip

deserializedMap := buf.readObj as Map
echo(deserializedMap.ordered)

prints

false

brian Thu 15 Nov 2012

That is by design since ordered state isn't serializable. One option would be to always use ordered (treemap) implementation in the decoder. It would be a bit slower, but might give more robust results which always match the text deserialized. I'd like to hear some feedback and support for that change before making it though

endragor Thu 15 Nov 2012

Why not add it as a deserialization option?

jodastephen Fri 16 Nov 2012

The test case just looks like a bug to me. "ordered" is a key part of the state and should be serialised.

bedla Mon 28 Jan 2013

I agree with jodastephen :)

SlimerDude Wed 18 Jun 2014

I've just been bit by this.

I was storing some data in a WebSession and was expecting my data to be regurgitated in the same state as it went in. As it stands my map data comes back in a different order than it went in.

You wouldn't expect the values of a list to come back all jumbled up! The same goes for an ordered map.

Could ordered and caseInsensitive be serialised with the map, and be read back first before the data?

brian Wed 18 Jun 2014

Promoted to ticket #2059 and assigned to brian

I think what I finally decided in JSON was to always deserialize maps in order. Its a bit slower, but simplest solution for "just works"

brian Thu 8 Jan 2015

Ticket resolved in 1.0.67

Change fantom deserialization to always use ordered maps to match the behavior in JSON. This doesn't actually maintain the ordered/case insensitive state - that would require redesigning the serialize syntax itself.

SlimerDude Thu 8 Jan 2015

Cool, I saw the LinkedHashMap change!

This doesn't actually maintain the ordered/case insensitive state

Fair enough, could a sentence to this effect be added to the docs, so it doesn't catch people out?

SlimerDude Fri 12 Jan 2018

I noted that the Fantom JS implementation doesn't have this change, which can (or did!) trip you up when passing data from a (Java) server to a (JS) browser.

I think this (untested) patch may be all that's needed:

diff -r b0eaa6515889 src/sys/js/fanx/ObjDecoder.js
--- a/src/sys/js/fanx/ObjDecoder.js	Thu Jan 11 09:57:00 2018 -0500
+++ b/src/sys/js/fanx/ObjDecoder.js	Fri Jan 12 14:11:19 2018 +0000
@@ -445,6 +445,7 @@
   var map = mapType == null
     ? fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type.toNullable())
     : fan.sys.Map.make(mapType);
+  map.m_ordered = true;
 
   // finish first pair
   this.consume(fanx_Token.COLON, "Expected ':'");

andy Fri 12 Jan 2018

Is there a test in test suite somewhere we can check against?

SlimerDude Fri 12 Jan 2018

I found this in /testSys/fan/TestSerialization.fan:

// test ordering
Str:Int m := verifySer("""["b":1, "a":2, "c":5, "e":3, "f":3]""",  ["b":1, "a":2, "c":5, "e":3, "f":3])
verifyEq(m.keys, ["b", "a", "c", "e", "f"])

If it happens to pass, my issue used Uri as the key.

andy Fri 12 Jan 2018

Thanks Steve -- I'm going to split this out into a sep ticket

Login or Signup to reply.