Skip to content

Commit ac31283

Browse files
authored
[json-node] Add copy() and unmodifible() for deep copy options (#302)
Ability to create a mutable deep copy and an immutable deep copy
1 parent 2e2255d commit ac31283

File tree

11 files changed

+168
-7
lines changed

11 files changed

+168
-7
lines changed

json-node/src/main/java/io/avaje/json/node/JsonArray.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ public String toString() {
3737
return text();
3838
}
3939

40+
@Override
41+
public JsonArray unmodifiable() {
42+
final var newList = new ArrayList<JsonNode>(children.size());
43+
for (JsonNode child : children) {
44+
newList.add(child.unmodifiable());
45+
}
46+
return of(newList);
47+
}
48+
49+
@Override
50+
public JsonArray copy() {
51+
final var newList = new ArrayList<JsonNode>(children.size());
52+
for (JsonNode child : children) {
53+
newList.add(child.copy());
54+
}
55+
return new JsonArray(newList);
56+
}
57+
4058
@Override
4159
public Type type() {
4260
return Type.ARRAY;

json-node/src/main/java/io/avaje/json/node/JsonBoolean.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package io.avaje.json.node;
22

3-
public final class JsonBoolean implements JsonNode {
3+
public final /*value*/ class JsonBoolean implements JsonNode {
44

55
private final boolean value;
66

@@ -17,6 +17,16 @@ public String toString() {
1717
return text();
1818
}
1919

20+
@Override
21+
public JsonBoolean unmodifiable() {
22+
return this;
23+
}
24+
25+
@Override
26+
public JsonBoolean copy() {
27+
return this;
28+
}
29+
2030
@Override
2131
public Type type() {
2232
return Type.BOOLEAN;

json-node/src/main/java/io/avaje/json/node/JsonDecimal.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import java.math.BigDecimal;
66

7-
public final class JsonDecimal implements JsonNumber {
7+
public final /*value*/ class JsonDecimal implements JsonNumber {
88

99
private final BigDecimal value;
1010

@@ -21,6 +21,16 @@ public String toString() {
2121
return text();
2222
}
2323

24+
@Override
25+
public JsonDecimal unmodifiable() {
26+
return this;
27+
}
28+
29+
@Override
30+
public JsonDecimal copy() {
31+
return this;
32+
}
33+
2434
@Override
2535
public Type type() {
2636
return Type.NUMBER;

json-node/src/main/java/io/avaje/json/node/JsonDouble.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import java.math.BigDecimal;
66

7-
public final class JsonDouble implements JsonNumber {
7+
public final /*value*/ class JsonDouble implements JsonNumber {
88

99
private final double value;
1010

@@ -21,6 +21,16 @@ public String toString() {
2121
return text();
2222
}
2323

24+
@Override
25+
public JsonDouble unmodifiable() {
26+
return this;
27+
}
28+
29+
@Override
30+
public JsonDouble copy() {
31+
return this;
32+
}
33+
2434
@Override
2535
public Type type() {
2636
return Type.NUMBER;

json-node/src/main/java/io/avaje/json/node/JsonInteger.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import java.math.BigDecimal;
66

7-
public final class JsonInteger implements JsonNumber {
7+
public final /*value*/ class JsonInteger implements JsonNumber {
88

99
private final int value;
1010

@@ -21,6 +21,16 @@ public String toString() {
2121
return text();
2222
}
2323

24+
@Override
25+
public JsonInteger unmodifiable() {
26+
return this;
27+
}
28+
29+
@Override
30+
public JsonInteger copy() {
31+
return this;
32+
}
33+
2434
@Override
2535
public Type type() {
2636
return Type.NUMBER;

json-node/src/main/java/io/avaje/json/node/JsonLong.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import java.math.BigDecimal;
66

7-
public final class JsonLong implements JsonNumber {
7+
public final /*value*/ class JsonLong implements JsonNumber {
88

99
private final long value;
1010

@@ -21,6 +21,16 @@ public String toString() {
2121
return text();
2222
}
2323

24+
@Override
25+
public JsonLong unmodifiable() {
26+
return this;
27+
}
28+
29+
@Override
30+
public JsonLong copy() {
31+
return this;
32+
}
33+
2434
@Override
2535
public Type type() {
2636
return Type.NUMBER;

json-node/src/main/java/io/avaje/json/node/JsonNode.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ public boolean isObject() {
7272
*/
7373
String text();
7474

75+
/**
76+
* Return an unmodifiable deep copy of the JsonNode.
77+
*/
78+
JsonNode unmodifiable();
79+
80+
/**
81+
* Return a mutable deep copy of the JsonNode.
82+
*/
83+
JsonNode copy();
84+
7585
/**
7686
* Find a node given a path using dot notation.
7787
* @param path The path in dot notation

json-node/src/main/java/io/avaje/json/node/JsonObject.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,24 @@ public String text() {
5151
return children.toString();
5252
}
5353

54+
@Override
55+
public JsonObject unmodifiable() {
56+
final var mapCopy = new LinkedHashMap<String,JsonNode>();
57+
for (Map.Entry<String, JsonNode> entry : children.entrySet()) {
58+
mapCopy.put(entry.getKey(), entry.getValue().unmodifiable());
59+
}
60+
return JsonObject.of(mapCopy);
61+
}
62+
63+
@Override
64+
public JsonObject copy() {
65+
final var mapCopy = new LinkedHashMap<String,JsonNode>();
66+
for (Map.Entry<String, JsonNode> entry : children.entrySet()) {
67+
mapCopy.put(entry.getKey(), entry.getValue().copy());
68+
}
69+
return new JsonObject(mapCopy);
70+
}
71+
5472
/**
5573
* Return true if the json object contains no elements.
5674
*/

json-node/src/main/java/io/avaje/json/node/JsonString.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package io.avaje.json.node;
22

3-
public final class JsonString implements JsonNode {
3+
public final /*value*/ class JsonString implements JsonNode {
44

55
private final String value;
66

@@ -17,6 +17,16 @@ public String toString() {
1717
return text();
1818
}
1919

20+
@Override
21+
public JsonString unmodifiable() {
22+
return this;
23+
}
24+
25+
@Override
26+
public JsonString copy() {
27+
return this;
28+
}
29+
2030
@Override
2131
public Type type() {
2232
return Type.STRING;

json-node/src/test/java/io/avaje/json/node/JsonArrayTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.stream.Collectors;
77

88
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
910

1011
class JsonArrayTest {
1112

@@ -87,4 +88,31 @@ void add() {
8788
assertThat(elements.get(4)).isInstanceOf(JsonObject.class);
8889
}
8990

91+
@Test
92+
void copy() {
93+
final JsonArray source = JsonArray.create()
94+
.add("foo")
95+
.add(JsonObject.create().add("b", 42));
96+
97+
JsonArray copy = source.copy();
98+
assertThat(copy.toString()).isEqualTo(source.toString());
99+
100+
copy.add("canMutate");
101+
assertThat(copy.size()).isEqualTo(3);
102+
assertThat(source.size()).isEqualTo(2);
103+
}
104+
105+
@Test
106+
void unmodifiable() {
107+
final JsonArray source = JsonArray.create()
108+
.add("foo")
109+
.add(JsonObject.create().add("b", 42));
110+
111+
JsonArray copy = source.unmodifiable();
112+
assertThat(copy.toString()).isEqualTo(source.toString());
113+
114+
assertThatThrownBy(() -> copy.add("canMutate"))
115+
.isInstanceOf(UnsupportedOperationException.class);
116+
}
117+
90118
}

0 commit comments

Comments
 (0)