Skip to content

Commit f587a27

Browse files
authored
Merge pull request #56 from MaryamZi/fix-7363
Fix toJson failing with repeated structured members at the same level
2 parents 06e613a + af9cb54 commit f587a27

File tree

2 files changed

+65
-23
lines changed

2 files changed

+65
-23
lines changed

ballerina/tests/to_json_test.bal

+60-22
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,13 @@ type TestRecord4 record {|
223223
function testToJsonWithCyclicValues() {
224224
json[] v1 = [];
225225
v1.push(v1);
226-
json|error r1 = trap toJsonWithCyclicValues(v1);
227-
test:assertTrue(r1 is error);
228-
error r1Err = <error> r1;
229-
test:assertEquals("the value has a cyclic reference", r1Err.message());
226+
json|error r1 = toJsonWithCyclicValues(v1);
227+
assertCyclicReferenceError(r1);
230228

231229
map<json> v2 = {};
232230
v2["val"] = v2;
233-
json|error r2 = trap toJsonWithCyclicValues(v2);
234-
test:assertTrue(r2 is error);
235-
error r2Err = <error> r2;
236-
test:assertEquals("the value has a cyclic reference", r2Err.message());
231+
json|error r2 = toJsonWithCyclicValues(v2);
232+
assertCyclicReferenceError(r2);
237233

238234
TestRecord4 v3 = {
239235
a: "a-v",
@@ -242,21 +238,17 @@ function testToJsonWithCyclicValues() {
242238
d: []
243239
};
244240
v3.d.push(v3);
245-
json|error r3 = trap toJsonWithCyclicValues(v3);
246-
test:assertTrue(r3 is error);
247-
error r3Err = <error> r3;
248-
test:assertEquals("the value has a cyclic reference", r3Err.message());
241+
json|error r3 = toJsonWithCyclicValues(v3);
242+
assertCyclicReferenceError(r3);
249243

250244
table<record {readonly int id; string name; record {} details;}> key (id) v4 =
251245
table [
252246
{id: 1023, name: "Joy", details: {}}
253247
];
254248
record {} details = v4.get(1023).details;
255249
details["tb"] = v4;
256-
json|error r4 = trap toJsonWithCyclicValues(v4);
257-
test:assertTrue(r4 is error);
258-
error r4Err = <error> r4;
259-
test:assertEquals("the value has a cyclic reference", r4Err.message());
250+
json|error r4 = toJsonWithCyclicValues(v4);
251+
assertCyclicReferenceError(r4);
260252
}
261253

262254
@test:Config
@@ -285,6 +277,48 @@ function testToJsonWithoutCyclicValuesWithRepeatedSimpleValueMembers() {
285277
test:assertNotExactEquals(jsonVal, jsonRes);
286278
}
287279

280+
type GreetingConf record {|
281+
readonly int id;
282+
record {| string message; |} greeting;
283+
record {| int count; int interval; |} repetition;
284+
|};
285+
286+
@test:Config
287+
function testToJsonWithoutCyclicValuesWithRepeatedStructuredMembers() {
288+
map<json> greetingConf = {greeting: {message: "hello world"}, repetition: {count: 2, interval: 5}};
289+
map<json>[] greetingConfs = [greetingConf, greetingConf];
290+
json arrJson = toJson(greetingConfs);
291+
test:assertEquals(greetingConfs, arrJson);
292+
test:assertNotExactEquals(greetingConfs, arrJson);
293+
294+
GreetingConf gc = {
295+
id: 1001,
296+
greeting: {message: "hello world"},
297+
repetition: {count: 2, interval: 5}
298+
};
299+
table<GreetingConf> tab = table [];
300+
tab.put(gc);
301+
tab.put({id: 1002, greeting: {message: "hello!"}, repetition: {count: 1, interval: 30}});
302+
tab.put(gc);
303+
json tabJson = toJson(tab);
304+
test:assertEquals(<json[]> [
305+
gc,
306+
{id: 1002, greeting: {message: "hello!"}, repetition: {count: 1, interval: 30}},
307+
gc
308+
], tabJson);
309+
310+
int[] arr = [1, 2, 3];
311+
map<int[]> mp = {
312+
a: arr,
313+
b: [],
314+
c: [3, 5, 6, 7],
315+
d: arr
316+
};
317+
json mapJson = toJson(mp);
318+
test:assertEquals(mp, mapJson);
319+
test:assertNotExactEquals(mp, mapJson);
320+
}
321+
288322
@test:Config
289323
function testToJsonWithCyclicValuesWithOtherSimpleValueMembers() {
290324
byte byteVal = 3;
@@ -307,12 +341,16 @@ function testToJsonWithCyclicValuesWithOtherSimpleValueMembers() {
307341
"p": false
308342
};
309343
jsonVal["q"] = jsonVal;
310-
json|error r1 = trap toJsonWithCyclicValues(jsonVal);
311-
test:assertTrue(r1 is error);
312-
error r1Err = <error> r1;
313-
test:assertEquals("the value has a cyclic reference", r1Err.message());
344+
json|error r1 = toJsonWithCyclicValues(jsonVal);
345+
assertCyclicReferenceError(r1);
346+
}
347+
348+
function toJsonWithCyclicValues(anydata val) returns json|error {
349+
return trap toJson(val);
314350
}
315351

316-
function toJsonWithCyclicValues(anydata val) returns json {
317-
return toJson(val);
352+
function assertCyclicReferenceError(json|error res) {
353+
test:assertTrue(res is error);
354+
error err = <error> res;
355+
test:assertEquals("the value has a cyclic reference", err.message());
318356
}

native/src/main/java/io/ballerina/lib/data/jsondata/json/Native.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ public static Object toJson(Object value, Set<Object> visitedValues) {
109109
int length = (int) listValue.getLength();
110110
Object[] convertedValues = new Object[length];
111111
for (int i = 0; i < length; i++) {
112-
convertedValues[i] = toJson(listValue.get(i), visitedValues);
112+
Object memValue = listValue.get(i);
113+
convertedValues[i] = toJson(memValue, visitedValues);
114+
visitedValues.remove(memValue);
113115
}
114116
return ValueCreator.createArrayValue(convertedValues, PredefinedTypes.TYPE_JSON_ARRAY);
115117
}
@@ -122,6 +124,7 @@ public static Object toJson(Object value, Set<Object> visitedValues) {
122124
for (BString entryKey : mapValue.getKeys()) {
123125
Object entryValue = mapValue.get(entryKey);
124126
jsonObject.put(getNameAnnotation(mapValue, entryKey), toJson(entryValue, visitedValues));
127+
visitedValues.remove(entryValue);
125128
}
126129

127130
return jsonObject;
@@ -134,6 +137,7 @@ public static Object toJson(Object value, Set<Object> visitedValues) {
134137
int index = 0;
135138
for (Object tableMember : tableValue.values()) {
136139
convertedValues[index++] = toJson(tableMember, visitedValues);
140+
visitedValues.remove(tableMember);
137141
}
138142
return ValueCreator.createArrayValue(convertedValues, PredefinedTypes.TYPE_JSON_ARRAY);
139143
}

0 commit comments

Comments
 (0)