Skip to content

Commit 5f211c1

Browse files
committed
add identity map
1 parent d9508dd commit 5f211c1

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package it.aboutbits.springboot.toolbox.util;
2+
3+
import it.aboutbits.springboot.toolbox.type.identity.EntityId;
4+
import it.aboutbits.springboot.toolbox.type.identity.Identified;
5+
import org.jspecify.annotations.NullMarked;
6+
import org.springframework.data.util.Streamable;
7+
8+
import java.util.Collection;
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
import java.util.function.Function;
12+
import java.util.stream.Collectors;
13+
import java.util.stream.Stream;
14+
15+
@NullMarked
16+
public class MapByIdentity<ID extends EntityId<?>, E extends Identified<ID>> extends HashMap<ID, E> {
17+
public MapByIdentity(int initialCapacity, float loadFactor) {
18+
super(initialCapacity, loadFactor);
19+
}
20+
21+
public MapByIdentity(int initialCapacity) {
22+
super(initialCapacity);
23+
}
24+
25+
public MapByIdentity() {
26+
super();
27+
}
28+
29+
public MapByIdentity(Map<? extends ID, ? extends E> m) {
30+
super(m);
31+
}
32+
33+
public static <ID extends EntityId<?>, E extends Identified<ID>> MapByIdentity<ID, E> of(Collection<? extends E> items) {
34+
var map = new MapByIdentity<ID, E>(items.size());
35+
items.forEach(item -> map.put(item.getId(), item));
36+
return map;
37+
}
38+
39+
public static <ID extends EntityId<?>, E extends Identified<ID>> MapByIdentity<ID, E> of(Stream<? extends E> items) {
40+
var collected = items.collect(Collectors.toMap(
41+
Identified::getId,
42+
Function.identity()
43+
));
44+
45+
return new MapByIdentity<>(collected);
46+
}
47+
48+
public static <ID extends EntityId<?>, E extends Identified<ID>> MapByIdentity<ID, E> of(Streamable<? extends E> items) {
49+
return of(items.toList());
50+
}
51+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package it.aboutbits.springboot.toolbox.util;
2+
3+
import it.aboutbits.springboot.toolbox.type.identity.EntityId;
4+
import it.aboutbits.springboot.toolbox.type.identity.Identified;
5+
import org.jspecify.annotations.NullMarked;
6+
import org.junit.jupiter.api.Nested;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.data.util.Streamable;
9+
10+
import java.util.List;
11+
import java.util.stream.Stream;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
15+
@NullMarked
16+
class MapByIdentityTest {
17+
@Nested
18+
class Of {
19+
@Test
20+
void collection() {
21+
// given
22+
var id1 = new TestEntityId(1);
23+
var id2 = new TestEntityId(2);
24+
25+
var entity1 = new TestEntity(id1);
26+
var entity2 = new TestEntity(id2);
27+
28+
var entities = List.of(entity1, entity2);
29+
30+
// when
31+
var result = MapByIdentity.of(entities);
32+
33+
// then
34+
assertThat(result).hasSize(2)
35+
.containsEntry(id1, entity1)
36+
.containsEntry(id2, entity2);
37+
}
38+
39+
@Test
40+
void stream() {
41+
// given
42+
var id1 = new TestEntityId(1);
43+
var id2 = new TestEntityId(2);
44+
45+
var entity1 = new TestEntity(id1);
46+
var entity2 = new TestEntity(id2);
47+
48+
var entityStream = Stream.of(entity1, entity2);
49+
50+
// when
51+
var result = MapByIdentity.of(entityStream);
52+
53+
// then
54+
assertThat(result).hasSize(2)
55+
.containsEntry(id1, entity1)
56+
.containsEntry(id2, entity2);
57+
}
58+
59+
@Test
60+
void streamable() {
61+
// given
62+
var id1 = new TestEntityId(1);
63+
var id2 = new TestEntityId(2);
64+
65+
var entity1 = new TestEntity(id1);
66+
var entity2 = new TestEntity(id2);
67+
68+
var streamable = Streamable.of(entity1, entity2);
69+
70+
// when
71+
var result = MapByIdentity.of(streamable);
72+
73+
// then
74+
assertThat(result).hasSize(2)
75+
.containsEntry(id1, entity1)
76+
.containsEntry(id2, entity2);
77+
}
78+
79+
@Test
80+
void emptyCollection() {
81+
// given
82+
var entities = List.<TestEntity>of();
83+
84+
// when
85+
var result = MapByIdentity.of(entities);
86+
87+
// then
88+
assertThat(result).isEmpty();
89+
}
90+
91+
@Test
92+
void emptyStream() {
93+
// given
94+
var emptyStream = Stream.<TestEntity>empty();
95+
96+
// when
97+
var result = MapByIdentity.of(emptyStream);
98+
99+
// then
100+
assertThat(result).isEmpty();
101+
}
102+
103+
@Test
104+
void emptyStreamable() {
105+
// given
106+
var emptyStreamable = Streamable.<TestEntity>empty();
107+
108+
// when
109+
var result = MapByIdentity.of(emptyStreamable);
110+
111+
// then
112+
assertThat(result).isEmpty();
113+
}
114+
}
115+
116+
private static class TestEntityId implements EntityId<Integer> {
117+
private final Integer value;
118+
119+
public TestEntityId(Integer value) {
120+
this.value = value;
121+
}
122+
123+
@Override
124+
public Integer value() {
125+
return value;
126+
}
127+
128+
@Override
129+
public int hashCode() {
130+
return value.hashCode();
131+
}
132+
133+
@Override
134+
public boolean equals(Object obj) {
135+
if (this == obj) return true;
136+
if (!(obj instanceof TestEntityId)) return false;
137+
var other = (TestEntityId) obj;
138+
return value.equals(other.value);
139+
}
140+
}
141+
142+
private static class TestEntity implements Identified<TestEntityId> {
143+
private final TestEntityId id;
144+
145+
public TestEntity(TestEntityId id) {
146+
this.id = id;
147+
}
148+
149+
@Override
150+
public TestEntityId getId() {
151+
return id;
152+
}
153+
}
154+
}

0 commit comments

Comments
 (0)