* added Java ZonedDateTimeSupport

Signed-off-by: Pan Li <panli@microsoft.com>
This commit is contained in:
Pan Li 2018-10-30 09:38:17 +08:00 коммит произвёл GitHub
Родитель a8cbcd44b7
Коммит 4e69ae2168
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 109 добавлений и 2 удалений

Просмотреть файл

@ -11,6 +11,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Constants {
public static final String DEFAULT_COLLECTION_NAME = "";
public static final String DEFAULT_REQUEST_UNIT = "4000";
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 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.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.microsoft.azure.documentdb.Document;
import com.microsoft.azure.spring.data.cosmosdb.Constants;
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.support.GenericConversionService;
import org.springframework.data.convert.EntityConverter;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.MappingException;
import org.springframework.util.Assert;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import static com.microsoft.azure.spring.data.cosmosdb.Constants.ISO_8601_COMPATIBLE_DATE_PATTERN;
public class MappingDocumentDbConverter
implements EntityConverter<DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty, Object, Document>,
ApplicationContextAware {
@ -62,6 +67,8 @@ public class MappingDocumentDbConverter
protected <R extends Object> R readInternal(final DocumentDbPersistentEntity<?> entity, Class<R> type,
final Document sourceDocument) {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(provideAdvancedSerializersModule());
try {
final DocumentDbPersistentProperty idProperty = entity.getIdProperty();
final Object idValue = sourceDocument.getId();
@ -75,11 +82,17 @@ public class MappingDocumentDbConverter
return objectMapper.readValue(jsonObject.toString(), type);
} 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);
}
}
private SimpleModule provideAdvancedSerializersModule() {
final SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializer());
return simpleModule;
}
@Override
@Deprecated
public void write(Object sourceEntity, Document document) {
@ -146,6 +159,7 @@ public class MappingDocumentDbConverter
/**
* Convert a property value to the value stored in CosmosDB
*
* @param fromPropertyValue
* @return
*/
@ -157,6 +171,9 @@ public class MappingDocumentDbConverter
// com.microsoft.azure.documentdb.JsonSerializable#set(String, T) cannot set values for Date and Enum correctly
if (fromPropertyValue instanceof Date) {
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) {
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);
}
}