@@ -6,6 +6,20 @@ require "big/json"
66require " uuid"
77require " uuid/json"
88
9+ enum JSONSerializableEnum
10+ Zero
11+ One
12+ Two
13+ OneHundred
14+ end
15+
16+ @[Flags ]
17+ enum JSONSerializableFlagEnum
18+ One
19+ Two
20+ OneHundred
21+ end
22+
923class JSONAttrValue (T )
1024 include JSON ::Serializable
1125
@@ -515,6 +529,44 @@ module JsonDiscriminatorBug
515529 end
516530end
517531
532+ record JSONAttrWithEnumValue , value : JSONSerializableEnum do
533+ include JSON ::Serializable
534+
535+ @[JSON ::Field (converter: Enum ::ValueConverter (JSONSerializableEnum ))]
536+ @value : JSONSerializableEnum
537+ end
538+
539+ record JSONAttrWithFlagEnumValue , value : JSONSerializableFlagEnum do
540+ include JSON ::Serializable
541+
542+ @[JSON ::Field (converter: Enum ::ValueConverter (JSONSerializableFlagEnum ))]
543+ @value : JSONSerializableFlagEnum
544+ end
545+
546+ abstract class SerializableFoo
547+ include JSON ::Serializable
548+
549+ module Converter
550+ def self.from_json (pull : JSON ::PullParser ) : SerializableFoo
551+ SerializableFoo .find.from_json(" {}" )
552+ end
553+ end
554+
555+ def self.find : SerializableFoo .class
556+ SerializableBar .as(SerializableFoo .class)
557+ end
558+ end
559+
560+ class SerializableBar < SerializableFoo
561+ @[JSON ::Field (converter: SerializableFoo ::Converter )]
562+ getter foo : SerializableFoo = SerializableBaz .new
563+ end
564+
565+ class SerializableBaz < SerializableFoo
566+ def initialize
567+ end
568+ end
569+
518570class JSONInitializeOpts
519571 include JSON ::Serializable
520572
@@ -1182,6 +1234,112 @@ describe "JSON mapping" do
11821234 end
11831235 end
11841236
1237+ describe " Enum::ValueConverter.from_json" do
1238+ it " normal enum" do
1239+ JSONAttrWithEnumValue .from_json(%( {"value": 0}) ).value.should eq(JSONSerializableEnum ::Zero )
1240+ JSONAttrWithEnumValue .from_json(%( {"value": 1}) ).value.should eq(JSONSerializableEnum ::One )
1241+ JSONAttrWithEnumValue .from_json(%( {"value": 2}) ).value.should eq(JSONSerializableEnum ::Two )
1242+ JSONAttrWithEnumValue .from_json(%( {"value": 3}) ).value.should eq(JSONSerializableEnum ::OneHundred )
1243+
1244+ expect_raises(JSON ::ParseException , %( Expected Int but was String) ) do
1245+ JSONAttrWithEnumValue .from_json(%( {"value": "3"}) )
1246+ end
1247+ expect_raises(JSON ::ParseException , %( Unknown enum JSONSerializableEnum value: 4) ) do
1248+ JSONAttrWithEnumValue .from_json(%( {"value": 4}) )
1249+ end
1250+ expect_raises(JSON ::ParseException , %( Unknown enum JSONSerializableEnum value: -1) ) do
1251+ JSONAttrWithEnumValue .from_json(%( {"value": -1}) )
1252+ end
1253+ expect_raises(JSON ::ParseException , %( Expected Int but was String) ) do
1254+ JSONAttrWithEnumValue .from_json(%( {"value": ""}) )
1255+ end
1256+
1257+ expect_raises(JSON ::ParseException , " Expected Int but was String" ) do
1258+ JSONAttrWithEnumValue .from_json(%( {"value": "one"}) )
1259+ end
1260+
1261+ expect_raises(JSON ::ParseException , " Expected Int but was BeginObject" ) do
1262+ JSONAttrWithEnumValue .from_json(%( {"value": {}}) )
1263+ end
1264+ expect_raises(JSON ::ParseException , " Expected Int but was BeginArray" ) do
1265+ JSONAttrWithEnumValue .from_json(%( {"value": []}) )
1266+ end
1267+ end
1268+
1269+ it " flag enum" do
1270+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 0}) ).value.should eq(JSONSerializableFlagEnum ::None )
1271+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 1}) ).value.should eq(JSONSerializableFlagEnum ::One )
1272+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 2}) ).value.should eq(JSONSerializableFlagEnum ::Two )
1273+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 4}) ).value.should eq(JSONSerializableFlagEnum ::OneHundred )
1274+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 5}) ).value.should eq(JSONSerializableFlagEnum ::OneHundred | JSONSerializableFlagEnum ::One )
1275+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 7}) ).value.should eq(JSONSerializableFlagEnum ::All )
1276+
1277+ expect_raises(JSON ::ParseException , %( Unknown enum JSONSerializableFlagEnum value: 8) ) do
1278+ JSONAttrWithFlagEnumValue .from_json(%( {"value": 8}) )
1279+ end
1280+ expect_raises(JSON ::ParseException , %( Unknown enum JSONSerializableFlagEnum value: -1) ) do
1281+ JSONAttrWithFlagEnumValue .from_json(%( {"value": -1}) )
1282+ end
1283+ expect_raises(JSON ::ParseException , %( Expected Int but was String) ) do
1284+ JSONAttrWithFlagEnumValue .from_json(%( {"value": ""}) )
1285+ end
1286+ expect_raises(JSON ::ParseException , " Expected Int but was String" ) do
1287+ JSONAttrWithFlagEnumValue .from_json(%( {"value": "one"}) )
1288+ end
1289+ expect_raises(JSON ::ParseException , " Expected Int but was BeginObject" ) do
1290+ JSONAttrWithFlagEnumValue .from_json(%( {"value": {}}) )
1291+ end
1292+ expect_raises(JSON ::ParseException , " Expected Int but was BeginArray" ) do
1293+ JSONAttrWithFlagEnumValue .from_json(%( {"value": []}) )
1294+ end
1295+ end
1296+ end
1297+
1298+ describe " Enum::ValueConverter.to_json" do
1299+ it " normal enum" do
1300+ klass = JSONAttrWithEnumValue
1301+
1302+ klass.new(JSONSerializableEnum ::One ).to_json.should eq %( {"value":1})
1303+ klass.from_json(klass.new(JSONSerializableEnum ::One ).to_json).value
1304+ .should eq(JSONSerializableEnum ::One )
1305+
1306+ klass.new(JSONSerializableEnum ::OneHundred ).to_json.should eq %( {"value":3})
1307+ klass.from_json(klass.new(JSONSerializableEnum ::OneHundred ).to_json).value
1308+ .should eq(JSONSerializableEnum ::OneHundred )
1309+
1310+ # undefined members can't be parsed back because the standard converter only accepts
1311+ # named members
1312+ klass.new(JSONSerializableEnum .new(42 )).to_json.should eq %( {"value":42})
1313+ end
1314+
1315+ it " flag enum" do
1316+ klass = JSONAttrWithFlagEnumValue
1317+
1318+ klass.new(JSONSerializableFlagEnum ::One ).to_json.should eq %( {"value":1})
1319+ klass.from_json(klass.new(JSONSerializableFlagEnum ::One ).to_json).value
1320+ .should eq(JSONSerializableFlagEnum ::One )
1321+
1322+ klass.new(JSONSerializableFlagEnum ::OneHundred ).to_json.should eq %( {"value":4})
1323+ klass.from_json(klass.new(JSONSerializableFlagEnum ::OneHundred ).to_json).value
1324+ .should eq(JSONSerializableFlagEnum ::OneHundred )
1325+
1326+ combined = JSONSerializableFlagEnum ::OneHundred | JSONSerializableFlagEnum ::One
1327+
1328+ klass.new(combined).to_json.should eq %( {"value":5})
1329+ klass.from_json(klass.new(combined).to_json).value.should eq(combined)
1330+
1331+ klass.new(JSONSerializableFlagEnum ::None ).to_json.should eq %( {"value":0})
1332+ klass.from_json(klass.new(JSONSerializableFlagEnum ::None ).to_json).value
1333+ .should eq(JSONSerializableFlagEnum ::None )
1334+
1335+ klass.new(JSONSerializableFlagEnum ::All ).to_json.should eq %( {"value":7})
1336+ klass.from_json(klass.new(JSONSerializableFlagEnum ::All ).to_json).value
1337+ .should eq(JSONSerializableFlagEnum ::All )
1338+
1339+ klass.new(JSONSerializableFlagEnum .new(42 )).to_json.should eq %( {"value":42})
1340+ end
1341+ end
1342+
11851343 describe " namespaced classes" do
11861344 it " lets default values use the object's own namespace" do
11871345 request = JSONNamespace ::FooRequest .from_json(%( {"foo":{}}) )
@@ -1201,4 +1359,8 @@ describe "JSON mapping" do
12011359 it " supports generic type variables in converters" do
12021360 JSONAttrWithGenericConverter (Time ::EpochConverter ).from_json(%( {"value":1459859781}) ).value.should eq(Time .unix(1459859781 ))
12031361 end
1362+
1363+ it " fixes #16141" do
1364+ SerializableFoo .find.from_json(" {}" ).should be_a(SerializableBar )
1365+ end
12041366end
0 commit comments