Skip to content

Commit f2c5e53

Browse files
authored
Make signal commands JSON serializable (#21854)
1 parent 1817cef commit f2c5e53

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

signals/src/main/java/com/vaadin/signals/Node.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import java.util.Map;
2020
import java.util.Objects;
2121

22+
import com.fasterxml.jackson.annotation.JsonSubTypes;
23+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
24+
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
2225
import com.fasterxml.jackson.databind.JsonNode;
2326
import com.fasterxml.jackson.databind.node.NullNode;
2427

@@ -29,6 +32,13 @@
2932
* signal data or an {@link Alias} node that allows multiple signal ids to
3033
* reference the same data.
3134
*/
35+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
36+
@JsonSubTypes(value = {
37+
38+
@Type(value = Node.Data.class, name = "d"),
39+
@Type(value = Node.Alias.class, name = "a")
40+
41+
})
3242
public sealed interface Node {
3343

3444
/**

signals/src/main/java/com/vaadin/signals/SignalCommand.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,42 @@
1818
import java.util.List;
1919
import java.util.Map;
2020

21+
import com.fasterxml.jackson.annotation.JsonSubTypes;
22+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
23+
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
2124
import com.fasterxml.jackson.databind.JsonNode;
2225
import com.vaadin.signals.ListSignal.ListPosition;
2326

2427
/**
2528
* A command triggered from a signal.
2629
*/
30+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
31+
@JsonSubTypes(value = {
32+
33+
@Type(value = SignalCommand.ValueCondition.class, name = "value"),
34+
@Type(value = SignalCommand.PositionCondition.class, name = "pos"),
35+
@Type(value = SignalCommand.KeyCondition.class, name = "key"),
36+
@Type(value = SignalCommand.LastUpdateCondition.class, name = "last"),
37+
38+
@Type(value = SignalCommand.AdoptAtCommand.class, name = "at"),
39+
@Type(value = SignalCommand.AdoptAsCommand.class, name = "as"),
40+
41+
@Type(value = SignalCommand.IncrementCommand.class, name = "inc"),
42+
@Type(value = SignalCommand.ClearCommand.class, name = "clear"),
43+
44+
@Type(value = SignalCommand.RemoveByKeyCommand.class, name = "removeKey"),
45+
@Type(value = SignalCommand.PutCommand.class, name = "put"),
46+
@Type(value = SignalCommand.PutIfAbsentCommand.class, name = "putAbsent"),
47+
48+
@Type(value = SignalCommand.InsertCommand.class, name = "insert"),
49+
@Type(value = SignalCommand.SetCommand.class, name = "set"),
50+
@Type(value = SignalCommand.RemoveCommand.class, name = "remove"),
51+
@Type(value = SignalCommand.ClearOwnerCommand.class, name = "clearOwner"),
52+
53+
@Type(value = SignalCommand.TransactionCommand.class, name = "tx"),
54+
@Type(value = SignalCommand.SnapshotCommand.class, name = "snapshot"),
55+
56+
})
2757
public sealed interface SignalCommand {
2858
/**
2959
* A signal command that sets the value of a signal.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.vaadin.signals;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.fail;
5+
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Set;
10+
import java.util.stream.Stream;
11+
12+
import org.junit.jupiter.api.Test;
13+
14+
import com.fasterxml.jackson.core.JsonProcessingException;
15+
import com.fasterxml.jackson.databind.JsonNode;
16+
import com.fasterxml.jackson.databind.ObjectMapper;
17+
import com.fasterxml.jackson.databind.node.TextNode;
18+
import com.vaadin.signals.ListSignal.ListPosition;
19+
20+
public class SignalCommandTest {
21+
private final ObjectMapper mapper = new ObjectMapper();
22+
private Set<Class<?>> assertedTypes = new HashSet<>();
23+
24+
@Test
25+
void json_serializeDeserializeCommands_commandsSerializable() {
26+
27+
Id id = Id.random();
28+
ListPosition pos = new ListPosition(id, id);
29+
JsonNode value = new TextNode("value");
30+
String key = "key";
31+
32+
assertSerializable(new SignalCommand.AdoptAsCommand(id, id, id, key));
33+
assertSerializable(new SignalCommand.AdoptAtCommand(id, id, id, pos));
34+
assertSerializable(new SignalCommand.ClearCommand(id, id));
35+
assertSerializable(new SignalCommand.ClearOwnerCommand(id, id));
36+
assertSerializable(new SignalCommand.IncrementCommand(id, id, 0));
37+
assertSerializable(
38+
new SignalCommand.InsertCommand(id, id, id, value, pos));
39+
assertSerializable(new SignalCommand.KeyCondition(id, id, key, id));
40+
assertSerializable(new SignalCommand.LastUpdateCondition(id, id, id));
41+
assertSerializable(
42+
new SignalCommand.PositionCondition(id, id, id, pos));
43+
assertSerializable(new SignalCommand.PutCommand(id, id, key, value));
44+
assertSerializable(
45+
new SignalCommand.PutIfAbsentCommand(id, id, id, key, value));
46+
assertSerializable(new SignalCommand.RemoveByKeyCommand(id, id, key));
47+
assertSerializable(new SignalCommand.RemoveCommand(id, id, id));
48+
assertSerializable(new SignalCommand.SetCommand(id, id, value));
49+
assertSerializable(new SignalCommand.SnapshotCommand(id,
50+
Map.of(Id.random(),
51+
new Node.Data(id, id, id, value, List.of(), Map.of()),
52+
Id.random(), new Node.Alias(id))));
53+
assertSerializable(new SignalCommand.TransactionCommand(id, List.of()));
54+
55+
Stream.of(SignalCommand.class.getPermittedSubclasses())
56+
.filter(type -> !type.isInterface())
57+
.filter(type -> !assertedTypes.contains(type))
58+
.forEach(type -> fail("Should test serialization for " + type));
59+
}
60+
61+
private void assertSerializable(SignalCommand command) {
62+
try {
63+
String json = mapper.writeValueAsString(command);
64+
SignalCommand deserialized = mapper.readValue(json,
65+
SignalCommand.class);
66+
assertEquals(command, deserialized);
67+
68+
assertedTypes.add(command.getClass());
69+
} catch (JsonProcessingException e) {
70+
fail(e);
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)