Skip to content

Commit 274aba2

Browse files
committed
fixup: fix all Collections.toMap
Signed-off-by: Todd Baert <[email protected]>
1 parent 4fcdc38 commit 274aba2

File tree

8 files changed

+91
-77
lines changed

8 files changed

+91
-77
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dev.openfeature.sdk;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" })
7+
abstract class AbstractStructure implements Structure {
8+
9+
protected final Map<String, Value> attributes;
10+
11+
AbstractStructure() {
12+
this.attributes = new HashMap<>();
13+
}
14+
15+
AbstractStructure(Map<String, Value> attributes) {
16+
this.attributes = attributes;
17+
}
18+
19+
/**
20+
* Get all values as their underlying primitives types.
21+
*
22+
* @return all attributes on the structure into a Map
23+
*/
24+
@Override
25+
public Map<String, Object> asObjectMap() {
26+
return attributes
27+
.entrySet()
28+
.stream()
29+
// custom collector, workaround for Collectors.toMap in JDK8
30+
// https://bugs.openjdk.org/browse/JDK-8148463
31+
.collect(HashMap::new,
32+
(accumulated, entry) -> accumulated.put(entry.getKey(), convertValue(entry.getValue())),
33+
HashMap::putAll);
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
package dev.openfeature.sdk;
22

3-
import lombok.EqualsAndHashCode;
4-
import lombok.ToString;
5-
63
import java.util.HashMap;
74
import java.util.HashSet;
85
import java.util.Map;
6+
import java.util.Optional;
97
import java.util.Set;
10-
import java.util.stream.Collectors;
8+
9+
import lombok.EqualsAndHashCode;
10+
import lombok.ToString;
1111

1212
/**
13-
* {@link ImmutableStructure} represents a potentially nested object type which is used to represent
13+
* {@link ImmutableStructure} represents a potentially nested object type which
14+
* is used to represent
1415
* structured data.
15-
* The ImmutableStructure is a Structure implementation which is threadsafe, and whose attributes can
16-
* not be modified after instantiation.
16+
* The ImmutableStructure is a Structure implementation which is threadsafe, and
17+
* whose attributes can
18+
* not be modified after instantiation. All references are clones.
1719
*/
1820
@ToString
1921
@EqualsAndHashCode
20-
@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
21-
public final class ImmutableStructure implements Structure {
22-
23-
private final Map<String, Value> attributes;
22+
@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" })
23+
public final class ImmutableStructure extends AbstractStructure {
2424

2525
/**
2626
* create an immutable structure with the empty attributes.
2727
*/
2828
public ImmutableStructure() {
29-
this(new HashMap<>());
29+
super();
3030
}
3131

3232
/**
@@ -35,10 +35,14 @@ public ImmutableStructure() {
3535
* @param attributes attributes.
3636
*/
3737
public ImmutableStructure(Map<String, Value> attributes) {
38-
Map<String, Value> copy = attributes.entrySet()
38+
super(new HashMap<>(attributes.entrySet()
3939
.stream()
40-
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().clone()));
41-
this.attributes = new HashMap<>(copy);
40+
.collect(HashMap::new,
41+
(accumulated, entry) -> accumulated.put(entry.getKey(),
42+
Optional.ofNullable(entry.getValue())
43+
.map(e -> e.clone())
44+
.orElse(null)),
45+
HashMap::putAll)));
4246
}
4347

4448
@Override
@@ -63,26 +67,11 @@ public Map<String, Value> asMap() {
6367
return attributes
6468
.entrySet()
6569
.stream()
66-
.collect(Collectors.toMap(
67-
Map.Entry::getKey,
68-
e -> getValue(e.getKey())
69-
));
70-
}
71-
72-
/**
73-
* Get all values, with primitives types.
74-
*
75-
* @return all attributes on the structure into a Map
76-
*/
77-
@Override
78-
public Map<String, Object> asObjectMap() {
79-
return attributes
80-
.entrySet()
81-
.stream()
82-
// custom collector, workaround for Collectors.toMap in JDK8
83-
// https://bugs.openjdk.org/browse/JDK-8148463
8470
.collect(HashMap::new,
85-
(accumulated, entry) -> accumulated.put(entry.getKey(), convertValue(entry.getValue())),
71+
(accumulated, entry) -> accumulated.put(entry.getKey(),
72+
Optional.ofNullable(entry.getValue())
73+
.map(e -> e.clone())
74+
.orElse(null)),
8675
HashMap::putAll);
8776
}
8877
}

src/main/java/dev/openfeature/sdk/MutableStructure.java

+6-25
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package dev.openfeature.sdk;
22

3-
import lombok.EqualsAndHashCode;
4-
import lombok.ToString;
5-
63
import java.time.Instant;
74
import java.util.HashMap;
85
import java.util.List;
96
import java.util.Map;
107
import java.util.Set;
11-
import java.util.stream.Collectors;
8+
9+
import lombok.EqualsAndHashCode;
10+
import lombok.ToString;
1211

1312
/**
1413
* {@link MutableStructure} represents a potentially nested object type which is used to represent
@@ -19,16 +18,14 @@
1918
@ToString
2019
@EqualsAndHashCode
2120
@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
22-
public class MutableStructure implements Structure {
23-
24-
protected final Map<String, Value> attributes;
21+
public class MutableStructure extends AbstractStructure {
2522

2623
public MutableStructure() {
27-
this.attributes = new HashMap<>();
24+
super();
2825
}
2926

3027
public MutableStructure(Map<String, Value> attributes) {
31-
this.attributes = new HashMap<>(attributes);
28+
super(attributes);
3229
}
3330

3431
@Override
@@ -92,20 +89,4 @@ public <T> MutableStructure add(String key, List<Value> value) {
9289
public Map<String, Value> asMap() {
9390
return new HashMap<>(this.attributes);
9491
}
95-
96-
/**
97-
* Get all values, with primitives types.
98-
*
99-
* @return all attributes on the structure into a Map
100-
*/
101-
@Override
102-
public Map<String, Object> asObjectMap() {
103-
return attributes
104-
.entrySet()
105-
.stream()
106-
.collect(Collectors.toMap(
107-
Map.Entry::getKey,
108-
e -> convertValue(getValue(e.getKey()))
109-
));
110-
}
11192
}

src/main/java/dev/openfeature/sdk/Structure.java

+12-11
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ public interface Structure {
4848
Map<String, Object> asObjectMap();
4949

5050
/**
51-
* convertValue is converting the object type Value in a primitive type.
51+
* Converts the Value into its equivalent primitive type.
5252
*
5353
* @param value - Value object to convert
54-
* @return an Object containing the primitive type.
54+
* @return an Object containing the primitive type, or null.
5555
*/
5656
default Object convertValue(Value value) {
5757

@@ -90,15 +90,14 @@ default Object convertValue(Value value) {
9090
if (value.isStructure()) {
9191
Structure s = value.asStructure();
9292
return s.asMap()
93-
.keySet()
93+
.entrySet()
9494
.stream()
95-
.collect(
96-
Collectors.toMap(
97-
key -> key,
98-
key -> convertValue(s.getValue(key))
99-
)
100-
);
95+
.collect(HashMap::new,
96+
(accumulated, entry) -> accumulated.put(entry.getKey(),
97+
convertValue(entry.getValue())),
98+
HashMap::putAll);
10199
}
100+
102101
throw new ValueNotConvertableError();
103102
}
104103

@@ -139,7 +138,9 @@ default <T extends Structure> Map<String, Value> merge(Function<Map<String, Valu
139138
*/
140139
static Structure mapToStructure(Map<String, Object> map) {
141140
return new MutableStructure(map.entrySet().stream()
142-
.filter(e -> e.getValue() != null)
143-
.collect(Collectors.toMap(Map.Entry::getKey, e -> objectToValue(e.getValue()))));
141+
.collect(HashMap::new,
142+
(accumulated, entry) -> accumulated.put(entry.getKey(),
143+
objectToValue(entry.getValue())),
144+
HashMap::putAll));
144145
}
145146
}

src/main/java/dev/openfeature/sdk/Value.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,7 @@ protected Value clone() {
275275
return new Value(copy);
276276
}
277277
if (this.isStructure()) {
278-
Map<String, Value> copy = this.asStructure().asMap().entrySet().stream().collect(Collectors.toMap(
279-
Map.Entry::getKey,
280-
e -> e.getValue().clone()
281-
));
282-
return new Value(new ImmutableStructure(copy));
278+
return new Value(new ImmutableStructure(this.asStructure().asMap()));
283279
}
284280
if (this.isInstant()) {
285281
Instant copy = Instant.ofEpochMilli(this.asInstant().toEpochMilli());
@@ -298,7 +294,7 @@ public static Value objectToValue(Object object) {
298294
if (object instanceof Value) {
299295
return (Value) object;
300296
} else if (object == null) {
301-
return null;
297+
return new Value();
302298
} else if (object instanceof String) {
303299
return new Value((String) object);
304300
} else if (object instanceof Boolean) {

src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java

+7
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,11 @@ void GettingAMissingValueShouldReturnNull() {
122122

123123
assertEquals(expected, structure.asObjectMap());
124124
}
125+
126+
@Test
127+
void constructorHandlesNullValue() {
128+
HashMap<String, Value> attrs = new HashMap<>();
129+
attrs.put("null", null);
130+
new ImmutableStructure(attrs);
131+
}
125132
}

src/test/java/dev/openfeature/sdk/StructureTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ void mapToStructureTest() {
9898
assertEquals(new Value(Instant.ofEpochSecond(0)), res.getValue("Instant"));
9999
assertEquals(new HashMap<>(), res.getValue("Map").asStructure().asMap());
100100
assertEquals(new Value(immutableContext), res.getValue("ImmutableContext"));
101-
assertNull(res.getValue("nullKey"));
101+
assertEquals(new Value((String)null), res.getValue("nullKey"));
102102
}
103103

104104
@Test

src/test/java/dev/openfeature/sdk/ValueTest.java

+5
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,9 @@ class Something {}
142142

143143
assertThrows(InstantiationException.class, ()-> new Value(list));
144144
}
145+
146+
@Test public void noOpFinalize() {
147+
Value val = new Value();
148+
val.finalize(); // doest nothing, but we want to defined in and make it final.
149+
}
145150
}

0 commit comments

Comments
 (0)