Add JavaTimeModule (#1065)

* Allow customize ObjectSerializer using a custom ObjectMapper

Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>

* Apply pull request suggestions

Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>

---------

Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
Co-authored-by: artur-ciocanu <artur.ciocanu@gmail.com>
Co-authored-by: salaboy <Salaboy@gmail.com>
This commit is contained in:
Matheus Cruz 2025-03-20 16:15:52 -03:00 committed by GitHub
parent 42b2d88216
commit ffbb5b39bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 121 additions and 5 deletions

View File

@ -127,6 +127,12 @@
<artifactId>grpc-inprocess</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -43,6 +43,10 @@ public class ObjectSerializer {
protected ObjectSerializer() {
}
protected ObjectMapper getObjectMapper() {
return OBJECT_MAPPER;
}
/**
* Serializes a given state object into byte array.
*
@ -70,7 +74,7 @@ public class ObjectSerializer {
}
// Not string, not primitive, so it is a complex type: we use JSON for that.
return OBJECT_MAPPER.writeValueAsBytes(state);
return getObjectMapper().writeValueAsBytes(state);
}
/**
@ -83,7 +87,7 @@ public class ObjectSerializer {
* @throws IOException In case content cannot be deserialized.
*/
public <T> T deserialize(byte[] content, TypeRef<T> type) throws IOException {
return deserialize(content, OBJECT_MAPPER.constructType(type.getType()));
return deserialize(content, getObjectMapper().constructType(type.getType()));
}
/**
@ -96,7 +100,7 @@ public class ObjectSerializer {
* @throws IOException In case content cannot be deserialized.
*/
public <T> T deserialize(byte[] content, Class<T> clazz) throws IOException {
return deserialize(content, OBJECT_MAPPER.constructType(clazz));
return deserialize(content, getObjectMapper().constructType(clazz));
}
private <T> T deserialize(byte[] content, JavaType javaType) throws IOException {
@ -138,7 +142,7 @@ public class ObjectSerializer {
}
}
return OBJECT_MAPPER.readValue(content, javaType);
return getObjectMapper().readValue(content, javaType);
}
/**
@ -149,7 +153,7 @@ public class ObjectSerializer {
* @throws IOException In case content cannot be parsed.
*/
public JsonNode parseNode(byte[] content) throws IOException {
return OBJECT_MAPPER.readTree(content);
return getObjectMapper().readTree(content);
}
/**

View File

@ -0,0 +1,23 @@
package io.dapr.serializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.dapr.client.ObjectSerializer;
public class CustomizableObjectSerializer extends ObjectSerializer implements DaprObjectSerializer {
private final ObjectMapper objectMapper;
public CustomizableObjectSerializer(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public ObjectMapper getObjectMapper() {
return objectMapper;
}
@Override
public String getContentType() {
return "application/json";
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2021 The Dapr Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
limitations under the License.
*/
package io.dapr.serializer;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.Objects;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.Serializable;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class CustomObjectSerializerTest {
private static final DaprObjectSerializer SERIALIZER =
new CustomizableObjectSerializer(new ObjectMapper()
.registerModule(new JavaTimeModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS));
public static class ObjectForTesting implements Serializable {
private ZonedDateTime time;
public ZonedDateTime getTime() {
return time;
}
public void setTime(ZonedDateTime time) {
this.time = time;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
ObjectForTesting that = (ObjectForTesting) o;
return Objects.equal(time, that.time);
}
@Override
public int hashCode() {
return Objects.hashCode(time);
}
}
@Test
public void serializeObjectForTesting() {
ObjectForTesting obj = new ObjectForTesting();
obj.setTime(ZonedDateTime.of(1900, 1, 1, 1, 1, 0, 0, ZoneId.of("UTC")));
String expectedResult =
"{\"time\":\"1900-01-01T01:01:00Z\"}";
String serializedValue;
try {
serializedValue = new String(SERIALIZER.serialize(obj));
assertEquals(expectedResult, serializedValue,
"FOUND:[[" + serializedValue + "]] \n but was EXPECTING: [[" + expectedResult + "]]");
} catch (IOException exception) {
fail(exception.getMessage());
}
}
}