Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 59b73ea

Browse files
committed
handle Jackson Serde annotations with custom JacksonAnnotationIntrospector
1 parent 1d9c0ca commit 59b73ea

File tree

6 files changed

+243
-53
lines changed

6 files changed

+243
-53
lines changed
Lines changed: 214 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,237 @@
11
package com.arangodb.serde;
22

3-
import com.arangodb.serde.jackson.Id;
4-
import com.arangodb.serde.jackson.Key;
3+
import com.arangodb.serde.jackson.*;
4+
import com.arangodb.serde.jackson.json.JacksonJsonSerdeProvider;
5+
import com.fasterxml.jackson.databind.JsonNode;
56
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
68
import com.fasterxml.jackson.databind.node.ObjectNode;
9+
import org.junit.jupiter.api.BeforeEach;
710
import org.junit.jupiter.api.Test;
811

12+
import java.io.IOException;
13+
import java.util.UUID;
14+
import java.util.function.BiFunction;
15+
import java.util.function.Function;
16+
917
import static org.assertj.core.api.Assertions.assertThat;
1018

1119
class JacksonInterferenceTest {
1220

1321
private final ObjectMapper mapper = new ObjectMapper();
22+
private final ArangoSerde serde = new JacksonJsonSerdeProvider().create();
23+
24+
private FooField fooField;
25+
private FooProp fooProp;
1426

15-
static class Foo {
27+
static class FooField {
1628
@Id
1729
public String myId;
18-
1930
@Key
2031
public String myKey;
32+
@Rev
33+
public String myRev;
34+
@From
35+
public String myFrom;
36+
@To
37+
public String myTo;
38+
}
39+
40+
static class FooProp {
41+
public String myId;
42+
public String myKey;
43+
public String myRev;
44+
public String myFrom;
45+
public String myTo;
46+
47+
@Id
48+
public String getMyId() {
49+
return myId;
50+
}
51+
52+
@Id
53+
public void setMyId(String myId) {
54+
this.myId = myId;
55+
}
56+
57+
@Key
58+
public String getMyKey() {
59+
return myKey;
60+
}
61+
62+
@Key
63+
public void setMyKey(String myKey) {
64+
this.myKey = myKey;
65+
}
66+
67+
@Rev
68+
public String getMyRev() {
69+
return myRev;
70+
}
71+
72+
@Rev
73+
public void setMyRev(String myRev) {
74+
this.myRev = myRev;
75+
}
2176

22-
Foo(Stringid, Stringkey) {
23-
myId = id;
24-
myKey = key;
77+
@From
78+
publicStringgetMyFrom() {
79+
returnmyFrom;
2580
}
81+
82+
@From
83+
public void setMyFrom(String myFrom) {
84+
this.myFrom = myFrom;
85+
}
86+
87+
@To
88+
public String getMyTo() {
89+
return myTo;
90+
}
91+
92+
@To
93+
public void setMyTo(String myTo) {
94+
this.myTo = myTo;
95+
}
96+
}
97+
98+
@BeforeEach
99+
void init() {
100+
fooField = new FooField();
101+
fooProp = new FooProp();
102+
103+
fooField.myId = "myId";
104+
fooProp.myId = "myId";
105+
106+
fooField.myKey = "myKey";
107+
fooProp.myKey = "myKey";
108+
109+
fooField.myRev = "myRev";
110+
fooProp.myRev = "myRev";
111+
112+
fooField.myFrom = "myFrom";
113+
fooProp.myFrom = "myFrom";
114+
115+
fooField.myTo = "myTo";
116+
fooProp.myTo = "myTo";
117+
}
118+
119+
@Test
120+
void serializeField() {
121+
// id
122+
testSerialize(fooField, "myId", fooField.myId, this::jacksonSerialize);
123+
testSerialize(fooField, "_id", fooField.myId, this::serdeSerialize);
124+
// key
125+
testSerialize(fooField, "myKey", fooField.myKey, this::jacksonSerialize);
126+
testSerialize(fooField, "_key", fooField.myKey, this::serdeSerialize);
127+
// rev
128+
testSerialize(fooField, "myRev", fooField.myRev, this::jacksonSerialize);
129+
testSerialize(fooField, "_rev", fooField.myRev, this::serdeSerialize);
130+
// from
131+
testSerialize(fooField, "myFrom", fooField.myFrom, this::jacksonSerialize);
132+
testSerialize(fooField, "_from", fooField.myFrom, this::serdeSerialize);
133+
// to
134+
testSerialize(fooField, "myTo", fooField.myTo, this::jacksonSerialize);
135+
testSerialize(fooField, "_to", fooField.myTo, this::serdeSerialize);
136+
}
137+
138+
@Test
139+
void serializeProp() {
140+
// id
141+
testSerialize(fooProp, "myId", fooProp.myId, this::jacksonSerialize);
142+
testSerialize(fooProp, "_id", fooProp.myId, this::serdeSerialize);
143+
// key
144+
testSerialize(fooProp, "myKey", fooProp.myKey, this::jacksonSerialize);
145+
testSerialize(fooProp, "_key", fooProp.myKey, this::serdeSerialize);
146+
// rev
147+
testSerialize(fooProp, "myRev", fooProp.myRev, this::jacksonSerialize);
148+
testSerialize(fooProp, "_rev", fooProp.myRev, this::serdeSerialize);
149+
// from
150+
testSerialize(fooProp, "myFrom", fooProp.myFrom, this::jacksonSerialize);
151+
testSerialize(fooProp, "_from", fooProp.myFrom, this::serdeSerialize);
152+
// to
153+
testSerialize(fooProp, "myTo", fooProp.myTo, this::jacksonSerialize);
154+
testSerialize(fooProp, "_to", fooProp.myTo, this::serdeSerialize);
155+
}
156+
157+
@Test
158+
void deserializeField() throws IOException {
159+
// id
160+
testDeserialize("myId", FooField.class, foo -> foo.myId, this::jacksonDeserialize);
161+
testDeserialize("_id", FooField.class, foo -> foo.myId, this::serdeDeserialize);
162+
// key
163+
testDeserialize("myKey", FooField.class, foo -> foo.myKey, this::jacksonDeserialize);
164+
testDeserialize("_key", FooField.class, foo -> foo.myKey, this::serdeDeserialize);
165+
// rev
166+
testDeserialize("myRev", FooField.class, foo -> foo.myRev, this::jacksonDeserialize);
167+
testDeserialize("_rev", FooField.class, foo -> foo.myRev, this::serdeDeserialize);
168+
// from
169+
testDeserialize("myFrom", FooField.class, foo -> foo.myFrom, this::jacksonDeserialize);
170+
testDeserialize("_from", FooField.class, foo -> foo.myFrom, this::serdeDeserialize);
171+
// to
172+
testDeserialize("myTo", FooField.class, foo -> foo.myTo, this::jacksonDeserialize);
173+
testDeserialize("_to", FooField.class, foo -> foo.myTo, this::serdeDeserialize);
26174
}
27175

28176
@Test
29-
void serialize() {
30-
Foo foo = new Foo("foo", "bar");
31-
ObjectNode node = mapper.convertValue(foo, ObjectNode.class);
32-
// assertThat(node.get("myId").textValue()).isEqualTo("foo");
33-
assertThat(node.get("myKey").textValue()).isEqualTo("bar");
177+
void deserializeProp() throws IOException {
178+
// id
179+
testDeserialize("myId", FooProp.class, FooProp::getMyId, this::jacksonDeserialize);
180+
testDeserialize("_id", FooProp.class, FooProp::getMyId, this::serdeDeserialize);
181+
// key
182+
testDeserialize("myKey", FooProp.class, FooProp::getMyKey, this::jacksonDeserialize);
183+
testDeserialize("_key", FooProp.class, FooProp::getMyKey, this::serdeDeserialize);
184+
// rev
185+
testDeserialize("myRev", FooProp.class, FooProp::getMyRev, this::jacksonDeserialize);
186+
testDeserialize("_rev", FooProp.class, FooProp::getMyRev, this::serdeDeserialize);
187+
// from
188+
testDeserialize("myFrom", FooProp.class, FooProp::getMyFrom, this::jacksonDeserialize);
189+
testDeserialize("_from", FooProp.class, FooProp::getMyFrom, this::serdeDeserialize);
190+
// to
191+
testDeserialize("myTo", FooProp.class, FooProp::getMyTo, this::jacksonDeserialize);
192+
testDeserialize("_to", FooProp.class, FooProp::getMyTo, this::serdeDeserialize);
193+
}
194+
195+
void testSerialize(Object data, String fieldName, String expectedValue, Function<Object, JsonNode> serializer) {
196+
JsonNode jn = serializer.apply(data).get(fieldName);
197+
assertThat(jn).isNotNull();
198+
assertThat(jn.textValue()).isEqualTo(expectedValue);
199+
}
200+
201+
<T> void testDeserialize(String fieldName, Class<T> clazz, Function<T, String> getter,
202+
BiFunction<byte[], Class<T>, T> deserializer) throws IOException {
203+
String fieldValue = UUID.randomUUID().toString();
204+
ObjectNode on = JsonNodeFactory.instance.objectNode().put(fieldName, fieldValue);
205+
byte[] bytes = mapper.writeValueAsBytes(on);
206+
T deser = deserializer.apply(bytes, clazz);
207+
assertThat(getter.apply(deser)).isEqualTo(fieldValue);
208+
}
209+
210+
private JsonNode jacksonSerialize(Object data) {
211+
try {
212+
return mapper.readTree(mapper.writeValueAsBytes(data));
213+
} catch (IOException e) {
214+
throw new RuntimeException(e);
215+
}
216+
}
217+
218+
private JsonNode serdeSerialize(Object data) {
219+
try {
220+
return mapper.readTree(serde.serialize(data));
221+
} catch (IOException e) {
222+
throw new RuntimeException(e);
223+
}
224+
}
225+
226+
private <T> T jacksonDeserialize(byte[] bytes, Class<T> clazz) {
227+
try {
228+
return mapper.readValue(bytes, clazz);
229+
} catch (IOException e) {
230+
throw new RuntimeException(e);
231+
}
232+
}
233+
234+
private <T> T serdeDeserialize(byte[] bytes, Class<T> clazz) {
235+
return serde.deserialize(bytes, clazz);
34236
}
35237
}
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package com.arangodb.serde.jackson;
22

3-
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
4-
import com.fasterxml.jackson.annotation.JsonInclude;
5-
import com.fasterxml.jackson.annotation.JsonProperty;
6-
73
import java.lang.annotation.ElementType;
84
import java.lang.annotation.Retention;
95
import java.lang.annotation.RetentionPolicy;
@@ -14,8 +10,5 @@
1410
*/
1511
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
1612
@Retention(RetentionPolicy.RUNTIME)
17-
@JacksonAnnotationsInside
18-
@JsonProperty("_from")
19-
@JsonInclude(JsonInclude.Include.NON_NULL)
2013
public @interface From {
2114
}
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package com.arangodb.serde.jackson;
22

3-
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
4-
import com.fasterxml.jackson.annotation.JsonInclude;
5-
import com.fasterxml.jackson.annotation.JsonProperty;
6-
73
import java.lang.annotation.ElementType;
84
import java.lang.annotation.Retention;
95
import java.lang.annotation.RetentionPolicy;
@@ -14,8 +10,5 @@
1410
*/
1511
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
1612
@Retention(RetentionPolicy.RUNTIME)
17-
@JacksonAnnotationsInside
18-
@JsonProperty("_id")
19-
@JsonInclude(JsonInclude.Include.NON_NULL)
2013
public @interface Id {
2114
}
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package com.arangodb.serde.jackson;
22

3-
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
4-
import com.fasterxml.jackson.annotation.JsonInclude;
5-
import com.fasterxml.jackson.annotation.JsonProperty;
6-
73
import java.lang.annotation.ElementType;
84
import java.lang.annotation.Retention;
95
import java.lang.annotation.RetentionPolicy;
@@ -14,8 +10,5 @@
1410
*/
1511
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
1612
@Retention(RetentionPolicy.RUNTIME)
17-
@JacksonAnnotationsInside
18-
@JsonProperty("_rev")
19-
@JsonInclude(JsonInclude.Include.NON_NULL)
2013
public @interface Rev {
2114
}
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package com.arangodb.serde.jackson;
22

3-
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
4-
import com.fasterxml.jackson.annotation.JsonInclude;
5-
import com.fasterxml.jackson.annotation.JsonProperty;
6-
73
import java.lang.annotation.ElementType;
84
import java.lang.annotation.Retention;
95
import java.lang.annotation.RetentionPolicy;
@@ -14,8 +10,5 @@
1410
*/
1511
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
1612
@Retention(RetentionPolicy.RUNTIME)
17-
@JacksonAnnotationsInside
18-
@JsonProperty("_to")
19-
@JsonInclude(JsonInclude.Include.NON_NULL)
2013
public @interface To {
2114
}

‎jackson-serde-json/src/main/java/com/arangodb/serde/jackson/internal/ArangoSerdeAnnotationIntrospector.java‎

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,57 @@
11
package com.arangodb.serde.jackson.internal;
22

3-
import com.arangodb.serde.jackson.Key;
3+
import com.arangodb.serde.jackson.*;
44
import com.fasterxml.jackson.annotation.JsonInclude;
55
import com.fasterxml.jackson.databind.PropertyName;
66
import com.fasterxml.jackson.databind.introspect.Annotated;
77
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
88

9+
import java.lang.annotation.Annotation;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
import java.util.Optional;
13+
914
class ArangoSerdeAnnotationIntrospector extends JacksonAnnotationIntrospector {
1015
private static final JsonInclude JSON_INCLUDE_NON_NULL = JsonIncludeNonNull.class.getAnnotation(JsonInclude.class);
16+
private static final Map<Class<? extends Annotation>, String> MAPPINGS;
17+
private static final Class<? extends Annotation>[] ANNOTATIONS;
18+
19+
static {
20+
MAPPINGS = new HashMap<>();
21+
MAPPINGS.put(Id.class, "_id");
22+
MAPPINGS.put(Key.class, "_key");
23+
MAPPINGS.put(Rev.class, "_rev");
24+
MAPPINGS.put(From.class, "_from");
25+
MAPPINGS.put(To.class, "_to");
26+
ANNOTATIONS = MAPPINGS.keySet().toArray(new Class[0]);
27+
}
1128

1229
@JsonInclude(JsonInclude.Include.NON_NULL)
1330
private static class JsonIncludeNonNull {
1431
}
1532

1633
@Override
1734
public PropertyName findNameForSerialization(Annotated a) {
18-
Key kann = _findAnnotation(a, Key.class);
19-
if (kann != null) {
20-
return PropertyName.construct("_key");
21-
}
22-
return super.findNameForSerialization(a);
35+
return Optional.ofNullable(findMapping(a)).orElseGet(() -> super.findNameForSerialization(a));
2336
}
2437

2538
@Override
2639
public PropertyName findNameForDeserialization(Annotated a) {
27-
Key kann = _findAnnotation(a, Key.class);
28-
if (kann != null) {
29-
return PropertyName.construct("_key");
30-
} else {
31-
return super.findNameForDeserialization(a);
40+
return Optional.ofNullable(findMapping(a)).orElseGet(() -> super.findNameForDeserialization(a));
41+
}
42+
43+
private PropertyName findMapping(Annotated a) {
44+
for (Map.Entry<Class<? extends Annotation>, String> e : MAPPINGS.entrySet()) {
45+
if (_hasAnnotation(a, e.getKey())) {
46+
return PropertyName.construct(e.getValue());
47+
}
3248
}
49+
return null;
3350
}
3451

3552
@Override
3653
public JsonInclude.Value findPropertyInclusion(Annotated a) {
37-
Key kann = _findAnnotation(a, Key.class);
38-
if (kann != null) {
54+
if (_hasOneOf(a, ANNOTATIONS)) {
3955
return new JsonInclude.Value(JSON_INCLUDE_NON_NULL);
4056
} else {
4157
return super.findPropertyInclusion(a);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /