/
VisitorMap.java
128 lines (105 loc) · 3.65 KB
/
VisitorMap.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.github.javaparser.utils;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.visitor.GenericVisitor;
import com.github.javaparser.ast.visitor.Visitable;
import com.github.javaparser.ast.visitor.VoidVisitor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* A facade for another java.util.Map that overrides the equals and hashcode calculation of the added nodes
* by using another visitor for those methods.
*/
public class VisitorMap<N extends Node, V> implements Map<N, V> {
// Cheat generics by removing them
private final Map<EqualsHashcodeOverridingFacade, V> innerMap;
private final GenericVisitor<Integer, Void> hashcodeVisitor;
private final GenericVisitor<Boolean, Visitable> equalsVisitor;
/**
* Wrap a map and use different visitors for equals and hashcode.
*/
public VisitorMap(GenericVisitor<Integer, Void> hashcodeVisitor, GenericVisitor<Boolean, Visitable> equalsVisitor) {
this.innerMap = new HashMap<>();
this.hashcodeVisitor = hashcodeVisitor;
this.equalsVisitor = equalsVisitor;
}
@Override
public int size() {
return innerMap.size();
}
@Override
public boolean isEmpty() {
return innerMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return innerMap.containsKey(new EqualsHashcodeOverridingFacade((N) key));
}
@Override
public boolean containsValue(Object value) {
return innerMap.containsValue(value);
}
@Override
public V get(Object key) {
return (V) innerMap.get(new EqualsHashcodeOverridingFacade((N) key));
}
@Override
public V put(N key, V value) {
return (V) innerMap.put(new EqualsHashcodeOverridingFacade(key), value);
}
private class EqualsHashcodeOverridingFacade implements Visitable {
private final N overridden;
public EqualsHashcodeOverridingFacade(N overridden) {
this.overridden = overridden;
}
@Override
public <R, A> R accept(GenericVisitor<R, A> v, A arg) {
throw new AssertionError();
}
@Override
public <A> void accept(VoidVisitor<A> v, A arg) {
throw new AssertionError();
}
@Override
public final int hashCode() {
return overridden.accept(hashcodeVisitor, null);
}
@Override
public boolean equals(final Object obj) {
if (obj == null || !(obj instanceof VisitorMap.EqualsHashcodeOverridingFacade)) {
return false;
}
return overridden.accept(equalsVisitor, ((EqualsHashcodeOverridingFacade) obj).overridden);
}
}
@Override
public V remove(Object key) {
return (V) innerMap.remove(key);
}
@Override
public void putAll(Map<? extends N, ? extends V> m) {
m.forEach((key, value) -> this.put(key,value));
}
@Override
public void clear() {
innerMap.clear();
}
@Override
public Set<N> keySet() {
return ((Map<EqualsHashcodeOverridingFacade, V>) innerMap).keySet().stream()
.map(k -> k.overridden)
.collect(Collectors.toSet());
}
@Override
public Collection<V> values() {
return innerMap.values();
}
@Override
public Set<Entry<N, V>> entrySet() {
return ((Map<EqualsHashcodeOverridingFacade, V>) innerMap).entrySet().stream()
.map(e -> new HashMap.SimpleEntry<N, V>(e.getKey().overridden, e.getValue()))
.collect(Collectors.toSet());
}
}