* added Java ZonedDateTimeSupport Signed-off-by: Pan Li <panli@microsoft.com>
This commit is contained in:
Родитель
a8cbcd44b7
Коммит
4e69ae2168
|
@ -11,6 +11,7 @@ import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
public static final String DEFAULT_COLLECTION_NAME = "";
|
public static final String DEFAULT_COLLECTION_NAME = "";
|
||||||
public static final String DEFAULT_REQUEST_UNIT = "4000";
|
public static final String DEFAULT_REQUEST_UNIT = "4000";
|
||||||
public static final boolean DEFAULT_INDEXINGPOLICY_AUTOMATIC = true;
|
public static final boolean DEFAULT_INDEXINGPOLICY_AUTOMATIC = true;
|
||||||
|
@ -27,5 +28,7 @@ public class Constants {
|
||||||
public static final String USER_AGENT_SUFFIX = "spring-data/";
|
public static final String USER_AGENT_SUFFIX = "spring-data/";
|
||||||
|
|
||||||
public static final String OBJECTMAPPER_BEAN_NAME = "cosmosdbObjectMapper";
|
public static final String OBJECTMAPPER_BEAN_NAME = "cosmosdbObjectMapper";
|
||||||
|
|
||||||
|
public static final String ISO_8601_COMPATIBLE_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:s:SSSXXX";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ package com.microsoft.azure.spring.data.cosmosdb.core.convert;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import com.microsoft.azure.documentdb.Document;
|
import com.microsoft.azure.documentdb.Document;
|
||||||
import com.microsoft.azure.spring.data.cosmosdb.Constants;
|
import com.microsoft.azure.spring.data.cosmosdb.Constants;
|
||||||
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.DocumentDbPersistentEntity;
|
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.DocumentDbPersistentEntity;
|
||||||
|
@ -20,15 +21,19 @@ import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.core.convert.support.GenericConversionService;
|
import org.springframework.core.convert.support.GenericConversionService;
|
||||||
import org.springframework.data.convert.EntityConverter;
|
import org.springframework.data.convert.EntityConverter;
|
||||||
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||||
import org.springframework.data.mapping.MappingException;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static com.microsoft.azure.spring.data.cosmosdb.Constants.ISO_8601_COMPATIBLE_DATE_PATTERN;
|
||||||
|
|
||||||
public class MappingDocumentDbConverter
|
public class MappingDocumentDbConverter
|
||||||
implements EntityConverter<DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty, Object, Document>,
|
implements EntityConverter<DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty, Object, Document>,
|
||||||
ApplicationContextAware {
|
ApplicationContextAware {
|
||||||
|
@ -62,6 +67,8 @@ public class MappingDocumentDbConverter
|
||||||
protected <R extends Object> R readInternal(final DocumentDbPersistentEntity<?> entity, Class<R> type,
|
protected <R extends Object> R readInternal(final DocumentDbPersistentEntity<?> entity, Class<R> type,
|
||||||
final Document sourceDocument) {
|
final Document sourceDocument) {
|
||||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
objectMapper.registerModule(provideAdvancedSerializersModule());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final DocumentDbPersistentProperty idProperty = entity.getIdProperty();
|
final DocumentDbPersistentProperty idProperty = entity.getIdProperty();
|
||||||
final Object idValue = sourceDocument.getId();
|
final Object idValue = sourceDocument.getId();
|
||||||
|
@ -75,11 +82,17 @@ public class MappingDocumentDbConverter
|
||||||
|
|
||||||
return objectMapper.readValue(jsonObject.toString(), type);
|
return objectMapper.readValue(jsonObject.toString(), type);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Failed to read the source document " + sourceDocument.toJson()
|
throw new IllegalStateException("Failed to read the source document " + sourceDocument.toJson()
|
||||||
+ " to target type " + type, e);
|
+ " to target type " + type, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SimpleModule provideAdvancedSerializersModule() {
|
||||||
|
final SimpleModule simpleModule = new SimpleModule();
|
||||||
|
simpleModule.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializer());
|
||||||
|
return simpleModule;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void write(Object sourceEntity, Document document) {
|
public void write(Object sourceEntity, Document document) {
|
||||||
|
@ -146,6 +159,7 @@ public class MappingDocumentDbConverter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a property value to the value stored in CosmosDB
|
* Convert a property value to the value stored in CosmosDB
|
||||||
|
*
|
||||||
* @param fromPropertyValue
|
* @param fromPropertyValue
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -157,6 +171,9 @@ public class MappingDocumentDbConverter
|
||||||
// com.microsoft.azure.documentdb.JsonSerializable#set(String, T) cannot set values for Date and Enum correctly
|
// com.microsoft.azure.documentdb.JsonSerializable#set(String, T) cannot set values for Date and Enum correctly
|
||||||
if (fromPropertyValue instanceof Date) {
|
if (fromPropertyValue instanceof Date) {
|
||||||
fromPropertyValue = ((Date) fromPropertyValue).getTime();
|
fromPropertyValue = ((Date) fromPropertyValue).getTime();
|
||||||
|
} else if (fromPropertyValue instanceof ZonedDateTime) {
|
||||||
|
fromPropertyValue = ((ZonedDateTime) fromPropertyValue)
|
||||||
|
.format(DateTimeFormatter.ofPattern(ISO_8601_COMPATIBLE_DATE_PATTERN));
|
||||||
} else if (fromPropertyValue instanceof Enum) {
|
} else if (fromPropertyValue instanceof Enum) {
|
||||||
fromPropertyValue = fromPropertyValue.toString();
|
fromPropertyValue = fromPropertyValue.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See LICENSE in the project root for
|
||||||
|
* license information.
|
||||||
|
*/
|
||||||
|
package com.microsoft.azure.spring.data.cosmosdb.core.convert;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
|
||||||
|
import static com.microsoft.azure.spring.data.cosmosdb.Constants.ISO_8601_COMPATIBLE_DATE_PATTERN;
|
||||||
|
|
||||||
|
public class ZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZonedDateTime deserialize(final JsonParser jsonParser, DeserializationContext deserializationContext)
|
||||||
|
throws IOException {
|
||||||
|
return parse(jsonParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public ZonedDateTime parse(final JsonParser jsonParser) throws IOException {
|
||||||
|
if (jsonParser.getValueAsString() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return ZonedDateTime.parse(jsonParser.getValueAsString(),
|
||||||
|
DateTimeFormatter.ofPattern(ISO_8601_COMPATIBLE_DATE_PATTERN));
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
throw new JsonParseException(jsonParser, jsonParser.getValueAsString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See LICENSE in the project root for
|
||||||
|
* license information.
|
||||||
|
*/
|
||||||
|
package com.microsoft.azure.spring.data.cosmosdb.core.convert;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class ZonedDateTimeDeserializerTest {
|
||||||
|
|
||||||
|
private static final String EXAMPLE_DATE_STRING = "2018-10-08T15:06:07:992Z";
|
||||||
|
private static final String ILLEGAL_DATE_STRING = "illegal-date-string";
|
||||||
|
private static final ZonedDateTime EXPECTED_SERIALIZED_ZONED_DATE_TIME
|
||||||
|
= ZonedDateTime.of(2018, 10, 8, 15, 6, 7, 992000000, ZoneId.of("Z"));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parse() throws IOException {
|
||||||
|
final JsonParser jsonParser = Mockito.mock(JsonParser.class);
|
||||||
|
when(jsonParser.getValueAsString()).thenReturn(EXAMPLE_DATE_STRING);
|
||||||
|
|
||||||
|
final ZonedDateTime zonedDateTime = new ZonedDateTimeDeserializer().parse(jsonParser);
|
||||||
|
|
||||||
|
assertThat(zonedDateTime.equals(EXPECTED_SERIALIZED_ZONED_DATE_TIME)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = JsonParseException.class)
|
||||||
|
public void testParseException() throws IOException {
|
||||||
|
final JsonParser jsonParser = Mockito.mock(JsonParser.class);
|
||||||
|
when(jsonParser.getValueAsString()).thenReturn(ILLEGAL_DATE_STRING);
|
||||||
|
|
||||||
|
new ZonedDateTimeDeserializer().parse(jsonParser);
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче