Skip to content

Commit 615d8bc

Browse files
🐛 fix: clashing IDs with same String representation for different Aggregate types (#15)
1 parent a2975dd commit 615d8bc

7 files changed

Lines changed: 148 additions & 0 deletions

File tree

src/main/java/com/dddheroes/heroesofddd/astrologers/write/AstrologersId.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
public record AstrologersId(String raw) {
66

7+
private final static String AGGREGATE_TYPE = "Astrologers";
8+
79
public AstrologersId {
810
if (raw == null || raw.isBlank()) {
911
throw new IllegalArgumentException("Astrologers id cannot be null or empty");
1012
}
13+
raw = withType(raw);
1114
}
1215

1316
public static AstrologersId of(String raw) {
@@ -22,4 +25,8 @@ public static AstrologersId random() {
2225
public String toString() {
2326
return raw;
2427
}
28+
29+
private static String withType(String id) {
30+
return id.startsWith(AGGREGATE_TYPE + ":") ? id : AGGREGATE_TYPE + ":" + id;
31+
}
2532
}

src/main/java/com/dddheroes/heroesofddd/calendar/write/CalendarId.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
public record CalendarId(String raw) {
66

7+
private final static String AGGREGATE_TYPE = "Calendar";
8+
79
public CalendarId {
810
if (raw == null || raw.isBlank()) {
911
throw new IllegalArgumentException("Calendar id cannot be null or empty");
1012
}
13+
raw = withType(raw);
1114
}
1215

1316
public static CalendarId of(String raw) {
@@ -22,4 +25,8 @@ public static CalendarId random() {
2225
public String toString() {
2326
return raw;
2427
}
28+
29+
private static String withType(String id) {
30+
return id.startsWith(AGGREGATE_TYPE + ":") ? id : AGGREGATE_TYPE + ":" + id;
31+
}
2532
}

src/main/java/com/dddheroes/heroesofddd/creaturerecruitment/write/DwellingId.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
public record DwellingId(String raw) {
66

7+
private final static String AGGREGATE_TYPE = "Dwelling";
8+
79
public DwellingId {
810
if (raw == null || raw.isBlank()) {
911
throw new IllegalArgumentException("Dwelling id cannot be null or empty");
1012
}
13+
raw = withType(raw);
1114
}
1215

1316
public static DwellingId of(String raw) {
@@ -22,4 +25,8 @@ public static DwellingId random() {
2225
public String toString() {
2326
return raw;
2427
}
28+
29+
private static String withType(String id) {
30+
return id.startsWith(AGGREGATE_TYPE + ":") ? id : AGGREGATE_TYPE + ":" + id;
31+
}
2532
}

src/main/java/com/dddheroes/heroesofddd/resourcespool/write/ResourcesPoolId.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
public record ResourcesPoolId(String raw) {
66

7+
private final static String AGGREGATE_TYPE = "ResourcesPool";
8+
79
public ResourcesPoolId {
810
if (raw == null || raw.isBlank()) {
911
throw new IllegalArgumentException("Resources Pool ID cannot be null or empty");
1012
}
13+
raw = withType(raw);
1114
}
1215

1316
public static ResourcesPoolId of(String raw) {
@@ -22,4 +25,8 @@ public static ResourcesPoolId random() {
2225
public String toString() {
2326
return raw;
2427
}
28+
29+
private static String withType(String id) {
30+
return id.startsWith(AGGREGATE_TYPE + ":") ? id : AGGREGATE_TYPE + ":" + id;
31+
}
2532
}

src/main/java/com/dddheroes/heroesofddd/shared/ArmyId.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
public record ArmyId(String raw) {
66

7+
private final static String AGGREGATE_TYPE = "Army";
8+
79
public ArmyId {
810
if (raw == null || raw.isBlank()) {
911
throw new IllegalArgumentException("Army id cannot be null or empty");
1012
}
13+
raw = withType(raw);
1114
}
1215

1316
public static ArmyId of(String raw) {
@@ -22,4 +25,8 @@ public static ArmyId random() {
2225
public String toString() {
2326
return raw;
2427
}
28+
29+
private static String withType(String id) {
30+
return id.startsWith(AGGREGATE_TYPE + ":") ? id : AGGREGATE_TYPE + ":" + id;
31+
}
2532
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.dddheroes.heroesofddd.creaturerecruitment.write;
2+
3+
import org.junit.jupiter.api.*;
4+
5+
import static org.junit.jupiter.api.Assertions.*;
6+
7+
class DwellingIdTest {
8+
9+
@Test
10+
void shouldThrowExceptionWhenRawIsNull() {
11+
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new DwellingId(null));
12+
assertEquals("Dwelling id cannot be null or empty", exception.getMessage());
13+
}
14+
15+
@Test
16+
void shouldThrowExceptionWhenRawIsEmpty() {
17+
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new DwellingId(""));
18+
assertEquals("Dwelling id cannot be null or empty", exception.getMessage());
19+
}
20+
21+
@Test
22+
void shouldAddAggregateTypeWhenNotPresent() {
23+
DwellingId dwellingId = new DwellingId("12345");
24+
assertEquals("Dwelling:12345", dwellingId.raw());
25+
}
26+
27+
@Test
28+
void shouldNotAddAggregateTypeWhenAlreadyPresent() {
29+
DwellingId dwellingId = new DwellingId("Dwelling:12345");
30+
assertEquals("Dwelling:12345", dwellingId.raw());
31+
}
32+
33+
@Test
34+
void factoryMethodShouldAddAggregateTypeWhenNotPresent() {
35+
DwellingId dwellingId = DwellingId.of("12345");
36+
assertEquals("Dwelling:12345", dwellingId.raw());
37+
}
38+
39+
@Test
40+
void factoryMethodShouldNotAddAggregateTypeWhenAlreadyPresent() {
41+
DwellingId dwellingId = new DwellingId("Dwelling:12345");
42+
assertEquals("Dwelling:12345", dwellingId.raw());
43+
}
44+
45+
@Test
46+
void shouldReturnRawStringInToString() {
47+
DwellingId dwellingId = new DwellingId("12345");
48+
assertEquals("Dwelling:12345", dwellingId.toString());
49+
}
50+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.dddheroes.heroesofddd.shared;
2+
3+
import com.dddheroes.heroesofddd.TestcontainersConfiguration;
4+
import com.dddheroes.heroesofddd.astrologers.write.AstrologersId;
5+
import com.dddheroes.heroesofddd.calendar.write.CalendarId;
6+
import com.dddheroes.heroesofddd.creaturerecruitment.write.DwellingId;
7+
import com.dddheroes.heroesofddd.resourcespool.write.ResourcesPoolId;
8+
import org.axonframework.eventhandling.DomainEventMessage;
9+
import org.axonframework.eventhandling.GenericDomainEventMessage;
10+
import org.axonframework.eventsourcing.eventstore.EventStore;
11+
import org.junit.jupiter.api.*;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.context.annotation.Import;
15+
16+
import java.util.Map;
17+
import java.util.UUID;
18+
19+
import static org.junit.jupiter.api.Assertions.*;
20+
21+
@Import(TestcontainersConfiguration.class)
22+
@SpringBootTest
23+
public class AggregateIdsDoNotClashTest {
24+
25+
@Autowired
26+
private EventStore eventStore;
27+
28+
@Test
29+
void givenSameIdValueForDifferentAggregateTypes_WhenStoreEvent_ThenDoNotClash() {
30+
// given
31+
var rawId = UUID.randomUUID().toString();
32+
var differentAggregateTypeIds = Map.of(
33+
"Army", ArmyId.of(rawId),
34+
"Astrologers", AstrologersId.of(rawId),
35+
"Calendar", CalendarId.of(rawId),
36+
"Dwelling", DwellingId.of(rawId),
37+
"ResourcesPool", ResourcesPoolId.of(rawId)
38+
);
39+
40+
// when/then
41+
assertDoesNotThrow(() -> {
42+
differentAggregateTypeIds.forEach(this::storeAggregateEvent);
43+
});
44+
}
45+
46+
private void storeAggregateEvent(String aggregateType, Object aggregateId) {
47+
eventStore.publish(domainEvent(aggregateType, aggregateId.toString(), "payload"));
48+
}
49+
50+
51+
private static DomainEventMessage<?> domainEvent(
52+
String aggregateType,
53+
String identifier,
54+
Object payload
55+
) {
56+
return new GenericDomainEventMessage<>(
57+
aggregateType,
58+
identifier,
59+
0,
60+
payload
61+
);
62+
}
63+
}

0 commit comments

Comments
 (0)