Skip to content

Commit b3a15e5

Browse files
committed
Add serialize/deserialize for ZonedDateTime using JavaTimeModule
Signed-off-by: Matheus Cruz <[email protected]>
1 parent 22d9874 commit b3a15e5

File tree

6 files changed

+258
-154
lines changed

6 files changed

+258
-154
lines changed

sdk/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
<artifactId>jackson-databind</artifactId>
4040
<version>2.15.1</version>
4141
</dependency>
42+
<dependency>
43+
<groupId>com.fasterxml.jackson.datatype</groupId>
44+
<artifactId>jackson-datatype-jsr310</artifactId>
45+
<version>2.15.1</version>
46+
</dependency>
4247
<dependency>
4348
<groupId>io.projectreactor</groupId>
4449
<artifactId>reactor-core</artifactId>

sdk/src/main/java/io/dapr/client/ObjectSerializer.java

+24-8
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
import com.fasterxml.jackson.databind.JavaType;
1919
import com.fasterxml.jackson.databind.JsonNode;
2020
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import com.fasterxml.jackson.databind.SerializationFeature;
22+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
2123
import com.google.protobuf.MessageLite;
2224
import io.dapr.client.domain.CloudEvent;
2325
import io.dapr.utils.TypeRef;
2426

2527
import java.io.IOException;
2628
import java.lang.reflect.Method;
29+
import java.util.Objects;
2730

2831
/**
2932
* Serializes and deserializes an internal object.
@@ -35,16 +38,29 @@ public class ObjectSerializer {
3538
*/
3639
protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
3740
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
41+
.registerModule(new JavaTimeModule())
42+
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
3843
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
3944

45+
protected ObjectMapper objectMapper;
46+
4047
/**
4148
* Default constructor to avoid class from being instantiated outside package but still inherited.
4249
*/
4350
protected ObjectSerializer() {
51+
this(OBJECT_MAPPER);
52+
}
53+
54+
protected ObjectSerializer(final ObjectMapper objectMapper) {
55+
this.objectMapper = Objects.requireNonNullElse(objectMapper, OBJECT_MAPPER);
56+
}
57+
58+
public static ObjectSerializer withObjectMapper(final ObjectMapper objectMapper) {
59+
return new ObjectSerializer(objectMapper);
4460
}
4561

4662
/**
47-
* Serializes a given state object into byte array.
63+
* Serializes a given state object into a byte array.
4864
*
4965
* @param state State object to be serialized.
5066
* @return Array of bytes[] with the serialized content.
@@ -70,7 +86,7 @@ public byte[] serialize(Object state) throws IOException {
7086
}
7187

7288
// Not string, not primitive, so it is a complex type: we use JSON for that.
73-
return OBJECT_MAPPER.writeValueAsBytes(state);
89+
return objectMapper.writeValueAsBytes(state);
7490
}
7591

7692
/**
@@ -83,7 +99,7 @@ public byte[] serialize(Object state) throws IOException {
8399
* @throws IOException In case content cannot be deserialized.
84100
*/
85101
public <T> T deserialize(byte[] content, TypeRef<T> type) throws IOException {
86-
return deserialize(content, OBJECT_MAPPER.constructType(type.getType()));
102+
return deserialize(content, objectMapper.constructType(type.getType()));
87103
}
88104

89105
/**
@@ -96,7 +112,7 @@ public <T> T deserialize(byte[] content, TypeRef<T> type) throws IOException {
96112
* @throws IOException In case content cannot be deserialized.
97113
*/
98114
public <T> T deserialize(byte[] content, Class<T> clazz) throws IOException {
99-
return deserialize(content, OBJECT_MAPPER.constructType(clazz));
115+
return deserialize(content, objectMapper.constructType(clazz));
100116
}
101117

102118
private <T> T deserialize(byte[] content, JavaType javaType) throws IOException {
@@ -138,7 +154,7 @@ private <T> T deserialize(byte[] content, JavaType javaType) throws IOException
138154
}
139155
}
140156

141-
return OBJECT_MAPPER.readValue(content, javaType);
157+
return objectMapper.readValue(content, javaType);
142158
}
143159

144160
/**
@@ -149,7 +165,7 @@ private <T> T deserialize(byte[] content, JavaType javaType) throws IOException
149165
* @throws IOException In case content cannot be parsed.
150166
*/
151167
public JsonNode parseNode(byte[] content) throws IOException {
152-
return OBJECT_MAPPER.readTree(content);
168+
return OBJECT_MAPPER.readTree(content);
153169
}
154170

155171
/**
@@ -161,7 +177,7 @@ public JsonNode parseNode(byte[] content) throws IOException {
161177
* @return Result as corresponding type.
162178
* @throws IOException if cannot deserialize primitive time.
163179
*/
164-
private static <T> T deserializePrimitives(byte[] content, JavaType javaType) throws IOException {
180+
public <T> T deserializePrimitives(byte[] content, JavaType javaType) throws IOException {
165181
if ((content == null) || (content.length == 0)) {
166182
if (javaType.hasRawClass(boolean.class)) {
167183
return (T) Boolean.FALSE;
@@ -198,6 +214,6 @@ private static <T> T deserializePrimitives(byte[] content, JavaType javaType) th
198214
return null;
199215
}
200216

201-
return OBJECT_MAPPER.readValue(content, javaType);
217+
return objectMapper.readValue(content, javaType);
202218
}
203219
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.dapr.serializer;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import io.dapr.client.ObjectSerializer;
5+
import io.dapr.utils.TypeRef;
6+
7+
import java.io.IOException;
8+
import java.util.Objects;
9+
10+
public class CustomizableDaprObjectSerializer implements DaprObjectSerializer {
11+
12+
private final ObjectSerializer delegate;
13+
14+
public CustomizableDaprObjectSerializer(final ObjectMapper objectMapper) {
15+
ObjectMapper nonNullableObjectMapper = Objects.requireNonNull(objectMapper);
16+
this.delegate = ObjectSerializer.withObjectMapper(nonNullableObjectMapper);
17+
}
18+
19+
@Override
20+
public byte[] serialize(Object o) throws IOException {
21+
return this.delegate.serialize(o);
22+
}
23+
24+
@Override
25+
public <T> T deserialize(byte[] data, TypeRef<T> type) throws IOException {
26+
return deserialize(data, type);
27+
}
28+
29+
@Override
30+
public String getContentType() {
31+
return "application/json";
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.dapr.serializer;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
5+
public interface DaprObjectSerializerFactory {
6+
7+
static DaprObjectSerializer createDefaultSerializer() {
8+
return new DefaultObjectSerializer();
9+
}
10+
11+
static DaprObjectSerializer createJacksonSerializer(final ObjectMapper objectMapper) {
12+
return new CustomizableDaprObjectSerializer(objectMapper);
13+
}
14+
}

sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.net.ServerSocket;
4242
import java.net.Socket;
4343
import java.time.Duration;
44+
import java.time.ZonedDateTime;
4445
import java.util.Arrays;
4546
import java.util.Collections;
4647
import java.util.HashMap;
@@ -345,6 +346,16 @@ public void invokeService() {
345346
assertEquals("hello world", mono.block());
346347
}
347348

349+
@Test
350+
public void invokeServiceWithZonedDateTime() {
351+
mockInterceptor.addRule()
352+
.get("http://" + sidecarIp + ":3000/v1.0/invoke/41/method/neworder")
353+
.respond("\"hello world\"");
354+
355+
Mono<String> mono = daprClientHttp.invokeMethod("41", "neworder", Map.of("zoned", ZonedDateTime.now()), HttpExtension.GET, null, String.class);
356+
assertEquals("hello world", mono.block());
357+
}
358+
348359
@Test
349360
public void invokeServiceNullResponse() {
350361
mockInterceptor.addRule()
@@ -486,4 +497,4 @@ public String getContentType() {
486497
return "application/xml";
487498
}
488499
}
489-
}
500+
}

0 commit comments

Comments
 (0)