From 33f0d23ec15cd9c9e42bbf555281bb88cc54bf9c Mon Sep 17 00:00:00 2001 From: Mikita Piatlitski Date: Wed, 20 Nov 2024 14:03:37 +0100 Subject: [PATCH 1/2] Add Instant<->Long conversion --- .../aerospike/convert/DateConverters.java | 22 +++++++++++++ .../MappingAerospikeConverterTypesTests.java | 33 ++++++++++++++++++- .../data/aerospike/sample/SampleClasses.java | 11 +++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/aerospike/convert/DateConverters.java b/src/main/java/org/springframework/data/aerospike/convert/DateConverters.java index ba0fa97a9..62e042e96 100644 --- a/src/main/java/org/springframework/data/aerospike/convert/DateConverters.java +++ b/src/main/java/org/springframework/data/aerospike/convert/DateConverters.java @@ -69,6 +69,8 @@ private DateConverters() { converters.add(LongToJava8LocalDateConverter.INSTANCE); converters.add(DurationToStringConverter.INSTANCE); converters.add(StringToDurationConverter.INSTANCE); + converters.add(InstantToLongConverter.INSTANCE); + converters.add(LongToInstantConverter.INSTANCE); if (JODA_TIME_IS_PRESENT) { converters.add(LocalDateToLongConverter.INSTANCE); @@ -295,4 +297,24 @@ public Duration convert(String source) { return Duration.parse(source); } } + + @WritingConverter + public enum InstantToLongConverter implements Converter { + INSTANCE; + + @Override + public Long convert(Instant source) { + return source == null ? null : source.toEpochMilli(); + } + } + + @ReadingConverter + public enum LongToInstantConverter implements Converter { + INSTANCE; + + @Override + public Instant convert(Long source) { + return source == null ? null : Instant.ofEpochMilli(source); + } + } } diff --git a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java index c35bbd391..f4ceb5140 100644 --- a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java +++ b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java @@ -16,12 +16,15 @@ import java.net.URL; import java.time.Duration; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiConsumer; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.within; import static org.springframework.data.aerospike.sample.SampleClasses.SimpleClass.SIMPLESET; import static org.springframework.data.aerospike.sample.SampleClasses.SimpleClassWithPersistenceConstructor.SIMPLESET2; import static org.springframework.data.aerospike.sample.SampleClasses.User.SIMPLESET3; @@ -672,6 +675,23 @@ void objectWithCalendarField(int converterOption) { new Bin("calendar", DateConverters.CalendarToMapConverter.INSTANCE.convert(calendar))); } + @ParameterizedTest + @ValueSource(ints = {0, 1}) + void objectWithInstantField(int converterOption) { + Instant instant = Instant.ofEpochMilli(Instant.now().toEpochMilli()); //to truncate nanos + DocumentWithInstant object = new DocumentWithInstant(id, instant); + + BiConsumer objectAssertFunction = (expected, actual) -> { + assertThat(expected.getId()).isEqualTo(actual.getId()); + assertThat(expected.getInstant()).isCloseTo(actual.getInstant(), within(1, ChronoUnit.MILLIS)); + }; + + assertWriteAndRead(converterOption, object, + "DocumentWithInstant", id, objectAssertFunction, + new Bin("@_class", DocumentWithInstant.class.getName()), + new Bin("instant", DateConverters.InstantToLongConverter.INSTANCE.convert(instant))); + } + @ParameterizedTest() @ValueSource(ints = {0, 1}) void objectWithDurationField(int converterOption) { @@ -784,6 +804,17 @@ private void assertWriteAndRead(int converterOption, String expectedSet, Object expectedUserKey, Bin... expectedBins) { + BiConsumer equalsAssertFunction = (a, b) -> assertThat(a).isEqualTo(b); + assertWriteAndRead(converterOption, object, expectedSet, expectedUserKey, equalsAssertFunction, + expectedBins); + } + + private void assertWriteAndRead(int converterOption, + T object, + String expectedSet, + Object expectedUserKey, + BiConsumer objectAssertFunction, + Bin... expectedBins) { MappingAerospikeConverter aerospikeConverter = getAerospikeMappingConverterByOption(converterOption); AerospikeWriteData forWrite = AerospikeWriteData.forWrite(NAMESPACE); @@ -808,7 +839,7 @@ private void assertWriteAndRead(int converterOption, @SuppressWarnings("unchecked") T actual = (T) aerospikeConverter.read(object.getClass(), forRead); - assertThat(actual).isEqualTo(object); + objectAssertFunction.accept(actual, object); } private boolean compareMaps(AerospikeDataSettings settings, Bin expected, Bin actual) { diff --git a/src/test/java/org/springframework/data/aerospike/sample/SampleClasses.java b/src/test/java/org/springframework/data/aerospike/sample/SampleClasses.java index dd19f00df..734a8d246 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/SampleClasses.java +++ b/src/test/java/org/springframework/data/aerospike/sample/SampleClasses.java @@ -39,6 +39,7 @@ import java.math.BigInteger; import java.net.URL; import java.time.Duration; +import java.time.Instant; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -988,6 +989,16 @@ public static class DocumentWithCalendar { private Calendar calendar; } + @Data + @AllArgsConstructor + @Document + public static class DocumentWithInstant { + @Id + private String id; + @Field + private Instant instant; + } + @Data @AllArgsConstructor @Document From b535aa068939d8418b4bbb66a61139967650a446 Mon Sep 17 00:00:00 2001 From: Mikita Piatlitski Date: Mon, 25 Nov 2024 11:35:40 +0100 Subject: [PATCH 2/2] user truncatedTo method --- .../aerospike/convert/MappingAerospikeConverterTypesTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java index f4ceb5140..81a028670 100644 --- a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java +++ b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java @@ -678,7 +678,7 @@ void objectWithCalendarField(int converterOption) { @ParameterizedTest @ValueSource(ints = {0, 1}) void objectWithInstantField(int converterOption) { - Instant instant = Instant.ofEpochMilli(Instant.now().toEpochMilli()); //to truncate nanos + Instant instant = Instant.now().truncatedTo(ChronoUnit.MILLIS); DocumentWithInstant object = new DocumentWithInstant(id, instant); BiConsumer objectAssertFunction = (expected, actual) -> {