1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.properties;
18
19 import java.util.AbstractMap.SimpleEntry;
20 import java.util.Collections;
21 import java.util.Enumeration;
22 import java.util.Iterator;
23 import java.util.LinkedHashSet;
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.Properties;
27 import java.util.Set;
28 import java.util.function.BiConsumer;
29 import java.util.function.BiFunction;
30 import java.util.function.Function;
31 import java.util.stream.Collectors;
32
33
34
35
36
37
38
39
40
41
42 public class OrderedProperties extends Properties {
43
44 private static final long serialVersionUID = 1L;
45
46
47
48
49 private final LinkedHashSet<Object> orderedKeys = new LinkedHashSet<>();
50
51 @Override
52 public synchronized void clear() {
53 orderedKeys.clear();
54 super.clear();
55 }
56
57 @Override
58 public synchronized Object compute(final Object key, final BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
59 final Object compute = super.compute(key, remappingFunction);
60 if (compute != null) {
61 orderedKeys.add(key);
62 }
63 return compute;
64 }
65
66 @Override
67 public synchronized Object computeIfAbsent(final Object key, final Function<? super Object, ? extends Object> mappingFunction) {
68 final Object computeIfAbsent = super.computeIfAbsent(key, mappingFunction);
69 if (computeIfAbsent != null) {
70 orderedKeys.add(key);
71 }
72 return computeIfAbsent;
73 }
74
75 @Override
76 public Set<Map.Entry<Object, Object>> entrySet() {
77 return orderedKeys.stream().map(k -> new SimpleEntry<>(k, get(k))).collect(Collectors.toCollection(LinkedHashSet::new));
78 }
79
80 @Override
81 public synchronized void forEach(final BiConsumer<? super Object, ? super Object> action) {
82 Objects.requireNonNull(action);
83 orderedKeys.forEach(k -> action.accept(k, get(k)));
84 }
85
86 @Override
87 public synchronized Enumeration<Object> keys() {
88 return Collections.enumeration(orderedKeys);
89 }
90
91 @Override
92 public Set<Object> keySet() {
93 return orderedKeys;
94 }
95
96 @Override
97 public synchronized Object merge(final Object key, final Object value,
98 final BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
99 orderedKeys.add(key);
100 return super.merge(key, value, remappingFunction);
101 }
102
103 @Override
104 public Enumeration<?> propertyNames() {
105 return Collections.enumeration(orderedKeys);
106 }
107
108 @Override
109 public synchronized Object put(final Object key, final Object value) {
110 final Object put = super.put(key, value);
111 if (put == null) {
112 orderedKeys.add(key);
113 }
114 return put;
115 }
116
117 @Override
118 public synchronized void putAll(final Map<? extends Object, ? extends Object> t) {
119 orderedKeys.addAll(t.keySet());
120 super.putAll(t);
121 }
122
123 @Override
124 public synchronized Object putIfAbsent(final Object key, final Object value) {
125 final Object putIfAbsent = super.putIfAbsent(key, value);
126 if (putIfAbsent == null) {
127 orderedKeys.add(key);
128 }
129 return putIfAbsent;
130 }
131
132 @Override
133 public synchronized Object remove(final Object key) {
134 final Object remove = super.remove(key);
135 if (remove != null) {
136 orderedKeys.remove(key);
137 }
138 return remove;
139 }
140
141 @Override
142 public synchronized boolean remove(final Object key, final Object value) {
143 final boolean remove = super.remove(key, value);
144 if (remove) {
145 orderedKeys.remove(key);
146 }
147 return remove;
148 }
149
150 @Override
151 public synchronized String toString() {
152
153 final int max = size() - 1;
154 if (max == -1) {
155 return "{}";
156 }
157 final StringBuilder sb = new StringBuilder();
158 final Iterator<Map.Entry<Object, Object>> it = entrySet().iterator();
159 sb.append('{');
160 for (int i = 0;; i++) {
161 final Map.Entry<Object, Object> e = it.next();
162 final Object key = e.getKey();
163 final Object value = e.getValue();
164 sb.append(key == this ? "(this Map)" : key.toString());
165 sb.append('=');
166 sb.append(value == this ? "(this Map)" : value.toString());
167 if (i == max) {
168 return sb.append('}').toString();
169 }
170 sb.append(", ");
171 }
172 }
173 }