Skip to content

Commit 65aa228

Browse files
committed
[wip]
1 parent ebb357f commit 65aa228

File tree

5 files changed

+235
-3
lines changed

5 files changed

+235
-3
lines changed

loom.eventsourcing.type/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ plugins {
44

55
dependencies {
66
api 'io.github.loom:loom.eventsourcing.contract:[0.0.1, 0.1.0)'
7-
api 'io.github.loom:loom.type:[0.0.1, 0.1.0)'
7+
api 'io.github.loom:loom.type:[0.1.0, 0.2.0)'
88
}
9+
10+
version = '0.1.0'
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package loom.eventsourcing;
2+
3+
import java.lang.reflect.ParameterizedType;
4+
import java.lang.reflect.Type;
5+
6+
class GenericType implements ParameterizedType {
7+
8+
private final Type rawType;
9+
private final Type[] typeArguments;
10+
11+
public GenericType(Type rawType, Type... typeArguments) {
12+
this.rawType = rawType;
13+
this.typeArguments = typeArguments.clone();
14+
}
15+
16+
@Override
17+
public Type[] getActualTypeArguments() {
18+
return typeArguments;
19+
}
20+
21+
@Override
22+
public Type getRawType() {
23+
return rawType;
24+
}
25+
26+
@Override
27+
public Type getOwnerType() {
28+
return null;
29+
}
30+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package loom.eventsourcing;
2+
3+
import java.lang.reflect.Type;
4+
import java.util.Optional;
5+
import java.util.function.Supplier;
6+
import loom.type.TypeStrategy;
7+
8+
public class StreamCommandTypeStrategy implements TypeStrategy {
9+
10+
private final Supplier<TypeStrategy> payloadStrategyFactory;
11+
private final String prefix;
12+
13+
public StreamCommandTypeStrategy(
14+
Supplier<TypeStrategy> payloadStrategyFactory
15+
) {
16+
this.payloadStrategyFactory = payloadStrategyFactory;
17+
this.prefix = "streamcommand";
18+
}
19+
20+
@Override
21+
public Optional<String> tryFormatType(Type type) {
22+
return Optional.empty();
23+
}
24+
25+
@Override
26+
public Optional<String> tryFormatTypeOf(Object value) {
27+
if (value instanceof StreamCommand) {
28+
StreamCommand<?> command = (StreamCommand<?>) value;
29+
Object payload = command.getPayload();
30+
TypeStrategy payloadStrategy = payloadStrategyFactory.get();
31+
String payloadType = payloadStrategy.formatTypeOf(payload);
32+
return Optional.of(prefix + ":" + payloadType);
33+
} else {
34+
return Optional.empty();
35+
}
36+
}
37+
38+
@Override
39+
public Optional<Type> tryResolveType(String formattedType) {
40+
String[] parts = formattedType.split(":", 2);
41+
if (parts.length == 2) {
42+
String prefix = parts[0];
43+
String formattedPayloadType = parts[1];
44+
TypeStrategy payloadStrategy = payloadStrategyFactory.get();
45+
Optional<Type> payloadType =
46+
payloadStrategy.tryResolveType(formattedPayloadType);
47+
if (prefix.equals(this.prefix)) {
48+
return payloadType.map(StreamCommandType::new);
49+
} else {
50+
return Optional.empty();
51+
}
52+
} else {
53+
return Optional.empty();
54+
}
55+
}
56+
57+
private static final class StreamCommandType extends GenericType {
58+
public StreamCommandType(Type payloadType) {
59+
super(StreamCommand.class, payloadType);
60+
}
61+
}
62+
}

loom.eventsourcing.type/src/main/java/loom/type/EventSourcingTypeStrategy.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import loom.eventsourcing.StreamCommand;
77
import loom.eventsourcing.StreamEvent;
88

9+
@Deprecated
910
public final class EventSourcingTypeStrategy implements TypeStrategy {
1011

1112
private final TypeStrategy payloadStrategy;
@@ -14,17 +15,22 @@ public EventSourcingTypeStrategy(TypeStrategy payloadStrategy) {
1415
this.payloadStrategy = payloadStrategy;
1516
}
1617

18+
@Override
19+
public Optional<String> tryFormatType(Type type) {
20+
return Optional.empty();
21+
}
22+
1723
@Override
1824
public Optional<String> tryFormatType(Object value) {
1925
if (value instanceof StreamCommand) {
2026
StreamCommand<?> command = (StreamCommand<?>) value;
2127
Object payload = command.getPayload();
22-
String payloadType = payloadStrategy.formatType(payload);
28+
String payloadType = payloadStrategy.formatTypeOf(payload);
2329
return Optional.of("stream-command:" + payloadType);
2430
} else if (value instanceof StreamEvent) {
2531
StreamEvent<?> event = (StreamEvent<?>) value;
2632
Object payload = event.getPayload();
27-
String payloadType = payloadStrategy.formatType(payload);
33+
String payloadType = payloadStrategy.formatTypeOf(payload);
2834
return Optional.of("stream-event:" + payloadType);
2935
} else {
3036
return Optional.empty();
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package test.loom.eventsourcing;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import autoparams.AutoSource;
6+
import autoparams.customization.Customization;
7+
import autoparams.mockito.MockitoCustomizer;
8+
import com.fasterxml.jackson.core.JsonProcessingException;
9+
import com.fasterxml.jackson.databind.JavaType;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import com.fasterxml.jackson.databind.type.TypeFactory;
12+
import java.lang.reflect.Type;
13+
import java.util.Optional;
14+
import loom.eventsourcing.StreamCommand;
15+
import loom.eventsourcing.StreamCommandTypeStrategy;
16+
import loom.type.TypeFormatter;
17+
import loom.type.TypeResolver;
18+
import loom.type.TypeStrategy;
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.params.ParameterizedTest;
21+
import test.loom.CreateUser;
22+
import test.loom.User;
23+
24+
class StreamCommandTypeStrategy_specs {
25+
26+
@ParameterizedTest
27+
@AutoSource
28+
@Customization(MockitoCustomizer.class)
29+
void sut_implements_TypeStrategy(StreamCommandTypeStrategy sut) {
30+
assertThat(sut).isInstanceOf(TypeStrategy.class);
31+
}
32+
33+
@ParameterizedTest
34+
@AutoSource
35+
@Customization(MockitoCustomizer.class)
36+
void tryFormatType_returns_empty(TypeResolver resolver) {
37+
StreamCommandTypeStrategy sut = new StreamCommandTypeStrategy(
38+
() -> TypeStrategy.create(TypeFormatter.forTypeName(), resolver));
39+
40+
Optional<String> actual = sut.tryFormatType(User.class);
41+
42+
assertThat(actual).isEmpty();
43+
}
44+
45+
@ParameterizedTest
46+
@AutoSource
47+
@Customization(MockitoCustomizer.class)
48+
void tryFormatTypeOf_correctly_formats_type_of_stream_command(
49+
TypeResolver resolver,
50+
StreamCommand<CreateUser> value
51+
) {
52+
StreamCommandTypeStrategy sut = new StreamCommandTypeStrategy(
53+
() -> TypeStrategy.create(TypeFormatter.forTypeName(), resolver));
54+
55+
Optional<String> actual = sut.tryFormatTypeOf(value);
56+
57+
assertThat(actual).contains("streamcommand:test.loom.CreateUser");
58+
}
59+
60+
@ParameterizedTest
61+
@AutoSource
62+
@Customization(MockitoCustomizer.class)
63+
void tryFormatTypeOf_returns_empty_for_non_stream_command_value(
64+
TypeResolver resolver,
65+
CreateUser value
66+
) {
67+
StreamCommandTypeStrategy sut = new StreamCommandTypeStrategy(
68+
() -> TypeStrategy.create(TypeFormatter.forTypeName(), resolver));
69+
70+
Optional<String> actual = sut.tryFormatTypeOf(value);
71+
72+
assertThat(actual).isEmpty();
73+
}
74+
75+
@ParameterizedTest
76+
@AutoSource
77+
@Customization(MockitoCustomizer.class)
78+
void tryResolveType_returns_empty_optional_for_invalid_formatted_type(
79+
TypeStrategy payloadStrategy,
80+
String formattedType
81+
) {
82+
StreamCommandTypeStrategy sut =
83+
new StreamCommandTypeStrategy(() -> payloadStrategy);
84+
85+
Optional<Type> actual = sut.tryResolveType(formattedType);
86+
87+
assertThat(actual).isEmpty();
88+
}
89+
90+
@Test
91+
void tryResolveType_returns_type_for_formatted_stream_command_type() {
92+
// Arrange
93+
StreamCommandTypeStrategy sut = new StreamCommandTypeStrategy(
94+
() -> TypeStrategy.create(
95+
TypeFormatter.forTypeName(),
96+
TypeResolver.forClassName()
97+
)
98+
);
99+
100+
String formattedType = "streamcommand:test.loom.CreateUser";
101+
102+
// Act
103+
Optional<Type> actual = sut.tryResolveType(formattedType);
104+
105+
// Assert
106+
assertThat(actual).isNotEmpty();
107+
}
108+
109+
@ParameterizedTest
110+
@AutoSource
111+
void tryResolveType_returns_correct_stream_command_type(
112+
StreamCommand<CreateUser> command,
113+
ObjectMapper mapper
114+
) throws JsonProcessingException {
115+
// Arrange
116+
StreamCommandTypeStrategy sut = new StreamCommandTypeStrategy(
117+
() -> TypeStrategy.create(
118+
TypeFormatter.forTypeName(),
119+
TypeResolver.forClassName()
120+
)
121+
);
122+
123+
// Act
124+
Type type = sut.resolveType("streamcommand:test.loom.CreateUser");
125+
126+
// Assert
127+
String json = mapper.writeValueAsString(command);
128+
JavaType javaType = TypeFactory.defaultInstance().constructType(type);
129+
Object value = mapper.readValue(json, javaType);
130+
assertThat(value).usingRecursiveComparison().isEqualTo(command);
131+
}
132+
}

0 commit comments

Comments
 (0)