Skip to content

Commit 3e01cb7

Browse files
committed
Added example of multiple upcasting transformations with different event types
1 parent ea33731 commit 3e01cb7

4 files changed

Lines changed: 222 additions & 14 deletions

File tree

samples/events-versioning/src/test/java/io/eventdriven/eventsversioning/downcasters/ChangedStructureTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public record ShoppingCartOpened(
2727
) {
2828
}
2929

30-
public static ShoppingCartEvent.ShoppingCartOpened Downcast(
30+
public static ShoppingCartEvent.ShoppingCartOpened downcast(
3131
ShoppingCartOpened newEvent
3232
) {
3333
return new ShoppingCartEvent.ShoppingCartOpened(
@@ -36,7 +36,7 @@ public static ShoppingCartEvent.ShoppingCartOpened Downcast(
3636
);
3737
}
3838

39-
public static ShoppingCartEvent.ShoppingCartOpened Downcast(
39+
public static ShoppingCartEvent.ShoppingCartOpened downcast(
4040
byte[] newEventJson
4141
) {
4242
var newEvent = Serializer.deserialize(newEventJson);
@@ -56,7 +56,7 @@ public void DowncastObjects_Should_BeForwardCompatible() {
5656
);
5757

5858
// When
59-
var oldEvent = Downcast(newEvent);
59+
var oldEvent = downcast(newEvent);
6060

6161
// Then
6262
assertNotNull(oldEvent);
@@ -74,7 +74,7 @@ public void DowncastJson_Should_BeForwardCompatible() {
7474
);
7575

7676
// When
77-
var oldEvent = Downcast(
77+
var oldEvent = downcast(
7878
Serializer.serialize(newEvent)
7979
);
8080

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package io.eventdriven.eventsversioning.transformations;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import io.eventdriven.eventsversioning.serialization.Serializer;
5+
import io.eventdriven.eventsversioning.v1.ShoppingCartEvent;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
import java.util.Optional;
11+
import java.util.UUID;
12+
import java.util.function.Function;
13+
14+
import static java.util.stream.Collectors.toMap;
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertTrue;
17+
18+
public class MultipleTransformationsWithDifferentEventTypesTests {
19+
public record Client(
20+
UUID id,
21+
String name
22+
) {
23+
public Client {
24+
if (name == null) {
25+
name = "Unknown";
26+
}
27+
}
28+
}
29+
30+
public record ShoppingCartOpened(
31+
UUID shoppingCartId,
32+
Client client
33+
) {
34+
}
35+
36+
public enum ShoppingCartStatus {
37+
Pending,
38+
Opened,
39+
Confirmed,
40+
Cancelled
41+
}
42+
43+
public record ShoppingCartInitializedWithStatus(
44+
UUID shoppingCartId,
45+
Client client,
46+
// Adding new not required property as nullable
47+
ShoppingCartStatus status
48+
) {
49+
}
50+
51+
public static ShoppingCartInitializedWithStatus upcastV1(
52+
JsonNode oldEvent
53+
) {
54+
return new ShoppingCartInitializedWithStatus(
55+
UUID.fromString(oldEvent.at("/shoppingCartId").asText()),
56+
new Client(
57+
UUID.fromString(oldEvent.at("/clientId").asText()),
58+
null
59+
),
60+
ShoppingCartStatus.Opened
61+
);
62+
}
63+
64+
public static ShoppingCartInitializedWithStatus upcastV2(
65+
ShoppingCartOpened oldEvent
66+
) {
67+
return new ShoppingCartInitializedWithStatus(
68+
oldEvent.shoppingCartId(),
69+
oldEvent.client(),
70+
ShoppingCartStatus.Opened
71+
);
72+
}
73+
74+
public class EventTransformations {
75+
private final Map<String, Function<byte[], Object>> jsonTransformations = new HashMap<>();
76+
77+
public Optional<Object> tryTransform(String eventTypeName, byte[] json) {
78+
if (!jsonTransformations.containsKey(eventTypeName)) {
79+
return Optional.empty();
80+
}
81+
82+
var transformJson = jsonTransformations.get(eventTypeName);
83+
84+
return Optional.of(transformJson.apply(json));
85+
}
86+
87+
public <Event> EventTransformations register(
88+
String eventTypeName,
89+
Function<JsonNode, Event> transformJson
90+
) {
91+
jsonTransformations.put(
92+
eventTypeName,
93+
json -> transformJson.apply(Serializer.deserialize(json))
94+
);
95+
return this;
96+
}
97+
98+
public <OldEvent, Event> EventTransformations register(
99+
Class<OldEvent> oldEventClass,
100+
String eventTypeName,
101+
Function<OldEvent, Event> transformEvent
102+
) {
103+
jsonTransformations.put(
104+
eventTypeName,
105+
json -> transformEvent.apply(Serializer.deserialize(oldEventClass, json)
106+
.orElseThrow(() -> new RuntimeException("Error deserializing")))
107+
);
108+
return this;
109+
}
110+
}
111+
112+
public class EventTypeMapping {
113+
private final Map<String, Class> mappings = new HashMap<>();
114+
115+
public <Event> EventTypeMapping register(Class<Event> eventClass, String... typeNames) {
116+
117+
for (var typeName : typeNames) {
118+
mappings.put(typeName, eventClass);
119+
}
120+
121+
return this;
122+
}
123+
124+
public Class map(String eventType) {
125+
return mappings.get(eventType);
126+
}
127+
}
128+
129+
public record EventSerializer(
130+
EventTypeMapping mapping,
131+
EventTransformations transformations
132+
) {
133+
public Optional<Object> deserialize(String eventTypeName, byte[] json) {
134+
return transformations.tryTransform(eventTypeName, json)
135+
.or(() -> Serializer.deserialize(mapping().map(eventTypeName), json));
136+
}
137+
}
138+
139+
@Test
140+
public void UpcastObjects_Should_BeForwardCompatible() {
141+
// Given
142+
final String eventTypeV1Name = "shopping_cart_initialized_v1";
143+
final String eventTypeV2Name = "shopping_cart_initialized_v2";
144+
final String eventTypeV3Name = "shopping_cart_initialized_v3";
145+
146+
var mapping = new EventTypeMapping()
147+
.register(ShoppingCartInitializedWithStatus.class,
148+
eventTypeV1Name,
149+
eventTypeV2Name,
150+
eventTypeV3Name
151+
);
152+
153+
var transformations = new EventTransformations()
154+
.register(eventTypeV1Name, MultipleTransformationsWithDifferentEventTypesTests::upcastV1)
155+
.register(ShoppingCartOpened.class, eventTypeV2Name, MultipleTransformationsWithDifferentEventTypesTests::upcastV2);
156+
157+
var serializer = new EventSerializer(mapping, transformations);
158+
159+
var eventV1 = new ShoppingCartEvent.ShoppingCartOpened(
160+
UUID.randomUUID(),
161+
UUID.randomUUID()
162+
);
163+
var eventV2 = new ShoppingCartOpened(
164+
UUID.randomUUID(),
165+
new Client(UUID.randomUUID(), "Oscar the Grouch")
166+
);
167+
var eventV3 = new ShoppingCartInitializedWithStatus(
168+
UUID.randomUUID(),
169+
new Client(UUID.randomUUID(), "Big Bird"),
170+
ShoppingCartStatus.Pending
171+
);
172+
173+
var events = new HashMap<String, byte[]>() {{
174+
put(eventTypeV1Name, Serializer.serialize(eventV1));
175+
put(eventTypeV2Name, Serializer.serialize(eventV2));
176+
put(eventTypeV3Name, Serializer.serialize(eventV3));
177+
}};
178+
179+
// When
180+
var deserializedEvents = events.entrySet().stream()
181+
.map(event -> serializer.deserialize(event.getKey(), event.getValue()))
182+
.filter(Optional::isPresent)
183+
.map(Optional::get)
184+
.filter(ShoppingCartInitializedWithStatus.class::isInstance)
185+
.map(ShoppingCartInitializedWithStatus.class::cast)
186+
.collect(toMap(ShoppingCartInitializedWithStatus::shoppingCartId, event -> event));
187+
188+
// Then
189+
assertEquals(3, deserializedEvents.size());
190+
191+
assertTrue(deserializedEvents.containsKey(eventV1.shoppingCartId()));
192+
var upcastedV1Event = deserializedEvents.get(eventV1.shoppingCartId());
193+
194+
assertEquals(eventV1.shoppingCartId(), upcastedV1Event.shoppingCartId());
195+
assertEquals(eventV1.clientId(), upcastedV1Event.client().id());
196+
assertEquals("Unknown", upcastedV1Event.client().name());
197+
assertEquals(ShoppingCartStatus.Opened, upcastedV1Event.status());
198+
199+
assertTrue(deserializedEvents.containsKey(eventV2.shoppingCartId()));
200+
var upcastedV2Event = deserializedEvents.get(eventV2.shoppingCartId());
201+
202+
assertEquals(eventV2.shoppingCartId(), upcastedV2Event.shoppingCartId());
203+
assertEquals(eventV2.client(), upcastedV2Event.client());
204+
assertEquals(ShoppingCartStatus.Opened, upcastedV2Event.status());
205+
206+
assertTrue(deserializedEvents.containsKey(eventV3.shoppingCartId()));
207+
assertEquals(eventV3, deserializedEvents.get(eventV3.shoppingCartId()));
208+
}
209+
}

samples/events-versioning/src/test/java/io/eventdriven/eventsversioning/upcasters/ChangedStructureTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public record ShoppingCartOpened(
2626
) {
2727
}
2828

29-
public static ShoppingCartOpened Upcast(
29+
public static ShoppingCartOpened upcast(
3030
ShoppingCartEvent.ShoppingCartOpened oldEvent
3131
) {
3232
return new ShoppingCartOpened(
@@ -35,7 +35,7 @@ public static ShoppingCartOpened Upcast(
3535
);
3636
}
3737

38-
public static ShoppingCartOpened Upcast(
38+
public static ShoppingCartOpened upcast(
3939
byte[] oldEventJson
4040
) {
4141
var oldEvent = Serializer.deserialize(oldEventJson);
@@ -55,7 +55,7 @@ public void UpcastObjects_Should_BeForwardCompatible() {
5555
var oldEvent = new ShoppingCartEvent.ShoppingCartOpened(UUID.randomUUID(), UUID.randomUUID());
5656

5757
// When
58-
var event = Upcast(oldEvent);
58+
var event = upcast(oldEvent);
5959

6060
// Then
6161
assertNotNull(event);
@@ -72,7 +72,7 @@ public void UpcastJson_Should_BeForwardCompatible() {
7272
var oldEvent = new ShoppingCartEvent.ShoppingCartOpened(UUID.randomUUID(), UUID.randomUUID());
7373

7474
// When
75-
var event = Upcast(
75+
var event = upcast(
7676
Serializer.serialize(oldEvent)
7777
);
7878

samples/events-versioning/src/test/java/io/eventdriven/eventsversioning/upcasters/NewRequiredPropertyFromMetadataTests.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
import java.util.UUID;
88

9-
import static org.junit.jupiter.api.Assertions.assertEquals;
10-
import static org.junit.jupiter.api.Assertions.assertNotNull;
9+
import static org.junit.jupiter.api.Assertions.*;
1110

1211
public class NewRequiredPropertyFromMetadataTests {
1312
public record EventMetadata(
@@ -22,7 +21,7 @@ public record ShoppingCartOpened(
2221
) {
2322
}
2423

25-
public static ShoppingCartOpened Upcast(
24+
public static ShoppingCartOpened upcast(
2625
ShoppingCartEvent.ShoppingCartOpened oldEvent,
2726
EventMetadata eventMetadata
2827
) {
@@ -33,7 +32,7 @@ public static ShoppingCartOpened Upcast(
3332
);
3433
}
3534

36-
public static ShoppingCartOpened Upcast(
35+
public static ShoppingCartOpened upcast(
3736
byte[] oldEventJson,
3837
byte[] eventMetadataJson
3938
) {
@@ -54,7 +53,7 @@ public void UpcastObjects_Should_BeForwardCompatible() {
5453
var eventMetadata = new EventMetadata(UUID.randomUUID());
5554

5655
// When
57-
var event = Upcast(oldEvent, eventMetadata);
56+
var event = upcast(oldEvent, eventMetadata);
5857

5958
// Then
6059
assertNotNull(event);
@@ -71,7 +70,7 @@ public void UpcastJson_Should_BeForwardCompatible() {
7170
var eventMetadata = new EventMetadata(UUID.randomUUID());
7271

7372
// When
74-
var event = Upcast(
73+
var event = upcast(
7574
Serializer.serialize(oldEvent),
7675
Serializer.serialize(eventMetadata)
7776
);

0 commit comments

Comments
 (0)