Skip to content

Commit 61705b5

Browse files
committed
🐛 FIX: smart key with grouping
1 parent 20596ec commit 61705b5

5 files changed

Lines changed: 100 additions & 0 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/survey/PatchDictionary.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import javax.validation.constraints.NotNull;
99

10+
import com.fasterxml.jackson.annotation.JsonIgnore;
11+
1012
/**
1113
* Wrapper around concrete storage for patch dictionary.
1214
*/
@@ -40,11 +42,13 @@ public PatchDictionary setDictionary(LinkedHashMap<PatchField, Object> dictionar
4042
return this;
4143
}
4244

45+
@JsonIgnore
4346
public PatchDictionary setNonTypedPatchDictionary(Map<PatchField, Object> patchDictionary) {
4447
this.dictionary = new LinkedHashMap<>(patchDictionary);
4548
return this;
4649
}
4750

51+
@JsonIgnore
4852
public boolean isEmpty() {
4953
return dictionary.isEmpty();
5054
}

sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/survey/PatchField.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
import javax.annotation.Nullable;
88
import javax.validation.constraints.NotNull;
99

10+
import com.fasterxml.jackson.annotation.JsonCreator;
11+
import com.fasterxml.jackson.annotation.JsonIgnore;
12+
import com.fasterxml.jackson.annotation.JsonValue;
13+
1014
/**
1115
* To be able to repeat some groups and make them belong together, the groupIndex was added.
1216
*/
@@ -23,6 +27,15 @@ public class PatchField implements Serializable {
2327
@Nullable
2428
private Integer groupIndex;
2529

30+
public PatchField() {
31+
}
32+
33+
@JsonCreator
34+
public PatchField(String field, @Nullable Integer groupIndex) {
35+
this.field = field;
36+
this.groupIndex = groupIndex;
37+
}
38+
2639
public static PatchField of(String field, Integer groupIndex) {
2740
return new PatchField().setField(field).setGroupIndex(groupIndex);
2841
}
@@ -50,10 +63,16 @@ public PatchField setGroupIndex(@Nullable Integer groupIndex) {
5063
return this;
5164
}
5265

66+
@JsonIgnore
5367
public Optional<Integer> getGroupNumber() {
5468
return Optional.ofNullable(groupIndex).map(index -> index + 1);
5569
}
5670

71+
@JsonValue
72+
public String toJsonValue() {
73+
return groupIndex == null ? field : field + "@" + groupIndex;
74+
}
75+
5776
@Override
5877
public boolean equals(Object o) {
5978
if (o == null || getClass() != o.getClass())
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package de.symeda.sormas.api.externalmessage.survey;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.databind.DeserializationContext;
6+
import com.fasterxml.jackson.databind.KeyDeserializer;
7+
8+
public class PatchFieldKeyDeserializer extends KeyDeserializer {
9+
10+
@Override
11+
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
12+
if (key == null || key.isBlank()) {
13+
return null;
14+
}
15+
16+
int atIndex = key.lastIndexOf('@');
17+
if (atIndex < 0) {
18+
return PatchField.of(key);
19+
}
20+
21+
String field = key.substring(0, atIndex);
22+
String indexPart = key.substring(atIndex + 1);
23+
24+
if (field.isBlank()) {
25+
throw ctxt.weirdKeyException(PatchField.class, key, "Field part is empty");
26+
}
27+
28+
try {
29+
Integer groupIndex = Integer.valueOf(indexPart);
30+
return PatchField.of(field, groupIndex);
31+
} catch (NumberFormatException e) {
32+
throw ctxt.weirdKeyException(PatchField.class, key, String.format("groupIndex must be an integer, was. [%s]", indexPart));
33+
}
34+
}
35+
}

sormas-backend/src/main/java/de/symeda/sormas/backend/json/ObjectMapperProvider.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
import com.fasterxml.jackson.core.JsonProcessingException;
2323
import com.fasterxml.jackson.databind.ObjectMapper;
2424
import com.fasterxml.jackson.databind.SerializationFeature;
25+
import com.fasterxml.jackson.databind.module.SimpleModule;
2526
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
2627

28+
import de.symeda.sormas.api.externalmessage.survey.PatchField;
29+
import de.symeda.sormas.api.externalmessage.survey.PatchFieldKeyDeserializer;
30+
2731
/**
2832
* Permits unified access to a pre-configured {@link ObjectMapper} instance.
2933
*/
@@ -72,6 +76,10 @@ private static ObjectMapper createObjectMapper() {
7276

7377
mapper.registerModule(new JavaTimeModule());
7478

79+
SimpleModule simpleModule = new SimpleModule();
80+
simpleModule.addKeyDeserializer(PatchField.class, new PatchFieldKeyDeserializer());
81+
mapper.registerModule(simpleModule);
82+
7583
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
7684

7785
return mapper;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package de.symeda.sormas.backend.externalmessage.survey;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.LinkedHashMap;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import com.fasterxml.jackson.core.JsonProcessingException;
10+
11+
import de.symeda.sormas.api.externalmessage.survey.PatchDictionary;
12+
import de.symeda.sormas.api.externalmessage.survey.PatchField;
13+
import de.symeda.sormas.backend.AbstractUnitTest;
14+
import de.symeda.sormas.backend.json.ObjectMapperProvider;
15+
16+
class PatchDictionarySerializationTest extends AbstractUnitTest {
17+
18+
@Test
19+
void test_serialization_deserialization_works() throws JsonProcessingException {
20+
// PREPARE
21+
LinkedHashMap<PatchField, Object> dictionary = new LinkedHashMap<>();
22+
dictionary.put(PatchField.of("fieldNameWithoutGroup"), 5);
23+
dictionary.put(PatchField.of("fieldNameWithGroup", 2), "toeiwjew");
24+
PatchDictionary initial = new PatchDictionary().setDictionary(dictionary);
25+
26+
// EXECUTE
27+
String json = ObjectMapperProvider.writeValueAsStringFailSafe(initial);
28+
29+
PatchDictionary actual = ObjectMapperProvider.getInstance().readValue(json, PatchDictionary.class);
30+
31+
// CHECK
32+
assertEquals(initial, actual);
33+
}
34+
}

0 commit comments

Comments
 (0)