Skip to content

Commit 3d9c022

Browse files
committed
Add MapOverlay.Builder
1 parent 5fe58c6 commit 3d9c022

2 files changed

Lines changed: 124 additions & 38 deletions

File tree

api/src/main/java/com/apicatalog/tree/io/morph/MapOverlay.java

Lines changed: 104 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Collection;
44
import java.util.Map;
55
import java.util.Map.Entry;
6+
import java.util.function.Function;
67
import java.util.stream.Stream;
78

89
import com.apicatalog.tree.io.Tree;
@@ -11,56 +12,130 @@
1112

1213
public class MapOverlay {
1314

15+
static final Function<Object, Object> REMOVED = Function.identity();
16+
1417
private final Object base;
15-
private final TreeAdapter baseAdapter;
1618

17-
private Collection<Object> keys;
18-
private Map<Object, Object> overlay;
19+
private final Map<Object, Object> overlay;
1920

20-
private MapOverlay(Object base, TreeAdapter baseAdapter) {
21+
MapOverlay(Object base, Map<Object, Object> overlay) {
2122
this.base = base;
22-
this.baseAdapter = baseAdapter;
23-
}
24-
25-
public static MapOverlay with(Tree tree) {
26-
return with(tree.node(), tree.adapter());
27-
}
28-
29-
public static MapOverlay with(Map<Object, Object> map) {
30-
return with(map, JavaAdapter.instance());
23+
this.overlay = overlay;
3124
}
3225

33-
public static MapOverlay with(Object map, TreeAdapter adapter) {
34-
return null;
26+
public Collection<?> keys(TreeAdapter adapter) {
27+
return keyStream(adapter).toList();
3528
}
3629

37-
public Collection<?> keys() {
38-
return keys;
30+
public Stream<?> keyStream(TreeAdapter adapter) {
31+
return Stream.concat(
32+
adapter.keyStream(base)
33+
.filter(key -> !overlay.containsKey(key)),
34+
overlay.entrySet().stream()
35+
.filter(entry -> !REMOVED.equals(entry.getValue()))
36+
.map(Entry::getKey));
3937
}
4038

41-
public Object property(Object key) {
39+
public Object property(Object key, TreeAdapter adapter) {
4240
if (overlay.containsKey(key)) {
43-
return overlay.get(key);
41+
final var value = overlay.get(key);
42+
if (REMOVED.equals(value)) {
43+
return null;
44+
}
45+
return value;
4446
}
45-
return baseAdapter.property(key, base);
47+
return adapter.property(key, base);
4648
}
4749

48-
public Object property(Object key, TreeAdapter keyAdapter) {
50+
public Object property(Object key, TreeAdapter keyAdapter, TreeAdapter adapter) {
4951
if (overlay.containsKey(key)) {
50-
return overlay.get(key);
52+
final var value = overlay.get(key);
53+
if (REMOVED.equals(value)) {
54+
return null;
55+
}
56+
return value;
5157
}
52-
return baseAdapter.property(key, keyAdapter, base);
58+
return adapter.property(key, keyAdapter, base);
5359
}
5460

55-
public Iterable<Entry<?, ?>> entries() {
56-
return entryStream().toList();
61+
public Iterable<Entry<?, ?>> entries(TreeAdapter adapter) {
62+
return entryStream(adapter).toList();
5763
}
5864

59-
public Stream<Entry<?, ?>> entryStream() {
65+
public Stream<Entry<?, ?>> entryStream(TreeAdapter adapter) {
6066
return Stream.concat(
61-
baseAdapter.entryStream(base)
62-
.filter(entry -> !overlay.containsKey(entry.getKey()) && keys.contains(entry.getKey())),
63-
overlay.entrySet().stream());
67+
adapter.entryStream(base)
68+
.filter(entry -> !overlay.containsKey(entry.getKey())),
69+
overlay.entrySet().stream()
70+
.filter(entry -> !REMOVED.equals(entry.getValue())));
71+
}
72+
73+
public static Builder newBuilder(Tree tree) {
74+
return newBuilder(tree.node(), tree.adapter());
75+
}
76+
77+
public static Builder newBuilder(Map<Object, Object> map) {
78+
return new Builder(map, JavaAdapter.instance());
79+
}
80+
81+
public static Builder newBuilder(Object map, TreeAdapter adapter) {
82+
if (adapter instanceof MorphAdapter morph) {
83+
return new Builder(map, morph.base);
84+
}
85+
return new Builder(map, adapter);
86+
}
87+
88+
public static class Builder {
89+
90+
private final Object base;
91+
private final TreeAdapter baseAdapter;
92+
93+
private Map<Object, Object> overlay;
94+
95+
private Builder(Object base, TreeAdapter baseAdapter) {
96+
this.base = base;
97+
this.baseAdapter = baseAdapter;
98+
}
99+
100+
public Builder remove(Object key) {
101+
overlay.put(key, REMOVED);
102+
return this;
103+
}
104+
105+
public Builder put(Object key, Object node, TreeAdapter nodeAdapter) {
106+
if (node instanceof Tree tree) {
107+
return put(key, tree);
108+
}
109+
if (nodeAdapter instanceof MorphAdapter morph
110+
&& baseAdapter.isEqualTo(morph.base)
111+
|| baseAdapter.isEqualTo(nodeAdapter)) {
112+
overlay.put(key, node);
113+
return this;
114+
}
115+
116+
overlay.put(key, new Tree(node, nodeAdapter));
117+
return this;
118+
}
119+
120+
public Builder put(Object key, Tree tree) {
121+
if (tree.adapter() instanceof MorphAdapter morph
122+
&& baseAdapter.isEqualTo(morph.base)
123+
|| baseAdapter.isEqualTo(tree.adapter())) {
124+
overlay.put(key, tree.node());
125+
return this;
126+
}
127+
return put(key, tree);
128+
}
129+
130+
public MapOverlay build() {
131+
return new MapOverlay(
132+
base,
133+
Map.copyOf(overlay));
134+
}
135+
136+
public Tree buildTree() {
137+
return new Tree(build(), new MorphAdapter(baseAdapter));
138+
}
64139
}
65140

66141
}

api/src/main/java/com/apicatalog/tree/io/morph/MorphAdapter.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010
import com.apicatalog.tree.io.Tree.NodeType;
1111
import com.apicatalog.tree.io.TreeAdapter;
1212

13-
class MorphAdapter implements TreeAdapter {
13+
public class MorphAdapter implements TreeAdapter {
1414

15-
private TreeAdapter base;
15+
protected final TreeAdapter base;
16+
17+
public MorphAdapter(TreeAdapter base) {
18+
this.base = base;
19+
}
1620

1721
@Override
1822
public boolean isEqualTo(TreeAdapter adapter) {
@@ -51,7 +55,7 @@ public boolean isBinary(Object node) {
5155
@Override
5256
public int size(Object node) {
5357
if (node instanceof MapOverlay map) {
54-
return map.keys().size();
58+
return map.keys(base).size();
5559
}
5660
return base.size(node);
5761
}
@@ -64,39 +68,47 @@ public boolean isMap(Object node) {
6468
@Override
6569
public Collection<?> keys(Object node) {
6670
if (node instanceof MapOverlay map) {
67-
return map.keys();
71+
return map.keys(base);
6872
}
6973
return base.keys(node);
7074
}
75+
76+
@Override
77+
public Stream<?> keyStream(Object node) {
78+
if (node instanceof MapOverlay map) {
79+
return map.keyStream(base);
80+
}
81+
return base.keyStream(node);
82+
}
7183

7284
@Override
7385
public Object property(Object key, Object node) {
7486
if (node instanceof MapOverlay map) {
75-
return map.property(key);
87+
return map.property(key, base);
7688
}
7789
return base.property(key, node);
7890
}
7991

8092
@Override
8193
public Object property(Object key, TreeAdapter keyAdapter, Object node) {
8294
if (node instanceof MapOverlay map) {
83-
return map.property(key, keyAdapter);
95+
return map.property(key, keyAdapter, base);
8496
}
8597
return base.property(key, keyAdapter, node);
8698
}
8799

88100
@Override
89101
public Iterable<Entry<?, ?>> entries(Object node) {
90102
if (node instanceof MapOverlay map) {
91-
return map.entries();
103+
return map.entries(base);
92104
}
93105
return base.entries(node);
94106
}
95107

96108
@Override
97109
public Stream<Entry<?, ?>> entryStream(Object node) {
98110
if (node instanceof MapOverlay map) {
99-
return map.entryStream();
111+
return map.entryStream(base);
100112
}
101113
return base.entryStream(node);
102114
}
@@ -185,5 +197,4 @@ public String asString(Object node) {
185197
public BigDecimal asDecimal(Object node) {
186198
return base.asDecimal(node);
187199
}
188-
189200
}

0 commit comments

Comments
 (0)