Skip to content

Commit 0804061

Browse files
DATAMONGO-2328 - Add missing target type conversions for field level type hints.
We now support Date to Long, Date to ObjectId, Script to String and other conversions for both reading and writing scenarios.
1 parent bcb135b commit 0804061

File tree

2 files changed

+134
-5
lines changed

2 files changed

+134
-5
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/AbstractMongoConverter.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@
1515
*/
1616
package org.springframework.data.mongodb.core.convert;
1717

18+
import static org.springframework.data.convert.ConverterBuilder.*;
19+
1820
import java.math.BigInteger;
21+
import java.util.Date;
1922

23+
import org.bson.types.Code;
2024
import org.bson.types.ObjectId;
2125
import org.springframework.beans.factory.InitializingBean;
2226
import org.springframework.core.convert.ConversionService;
@@ -93,6 +97,21 @@ private void initializeConverters() {
9397
conversionService.addConverter(BigIntegerToObjectIdConverter.INSTANCE);
9498
}
9599

100+
if (!conversionService.canConvert(Date.class, Long.class)) {
101+
conversionService.addConverter(writing(Date.class, Long.class, Date::getTime).getWritingConverter());
102+
}
103+
104+
if (!conversionService.canConvert(Long.class, Date.class)) {
105+
conversionService.addConverter(reading(Long.class, Date.class, Date::new).getReadingConverter());
106+
}
107+
108+
if (!conversionService.canConvert(ObjectId.class, Date.class)) {
109+
110+
conversionService.addConverter(
111+
reading(ObjectId.class, Date.class, objectId -> new Date(objectId.getTimestamp())).getReadingConverter());
112+
}
113+
114+
conversionService.addConverter(reading(Code.class, String.class, Code::getCode).getReadingConverter());
96115
conversions.registerConvertersIn(conversionService);
97116
}
98117

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.mockito.Mock;
4141
import org.mockito.Mockito;
4242
import org.mockito.junit.MockitoJUnitRunner;
43-
4443
import org.springframework.aop.framework.ProxyFactory;
4544
import org.springframework.beans.ConversionNotSupportedException;
4645
import org.springframework.beans.factory.annotation.Value;
@@ -1943,6 +1942,16 @@ public void mapsValueToExplicitTargetType() {
19431942
assertThat(target.get("script")).isEqualTo(new Code(source.script));
19441943
}
19451944

1945+
@Test // DATAMONGO-2328
1946+
public void readsScriptAsStringWhenAnnotatedWithFieldTargetType() {
1947+
1948+
String reference = "if (a > b) a else b";
1949+
WithExplicitTargetTypes target = converter.read(WithExplicitTargetTypes.class,
1950+
new org.bson.Document("script", new Code(reference)));
1951+
1952+
assertThat(target.script).isEqualTo(reference);
1953+
}
1954+
19461955
@Test // DATAMONGO-1849
19471956
public void mapsCollectionValueToExplicitTargetType() {
19481957

@@ -1968,6 +1977,96 @@ public void mapsBigDecimalToDecimal128WhenAnnotatedWithFieldTargetType() {
19681977
assertThat(target.get("bigDecimal")).isEqualTo(new Decimal128(source.bigDecimal));
19691978
}
19701979

1980+
@Test // DATAMONGO-2328
1981+
public void mapsDateToLongWhenAnnotatedWithFieldTargetType() {
1982+
1983+
WithExplicitTargetTypes source = new WithExplicitTargetTypes();
1984+
source.dateAsLong = new Date();
1985+
1986+
org.bson.Document target = new org.bson.Document();
1987+
converter.write(source, target);
1988+
1989+
assertThat(target.get("dateAsLong")).isEqualTo(source.dateAsLong.getTime());
1990+
}
1991+
1992+
@Test // DATAMONGO-2328
1993+
public void readsLongAsDateWhenAnnotatedWithFieldTargetType() {
1994+
1995+
Date reference = new Date();
1996+
WithExplicitTargetTypes target = converter.read(WithExplicitTargetTypes.class,
1997+
new org.bson.Document("dateAsLong", reference.getTime()));
1998+
1999+
assertThat(target.dateAsLong).isEqualTo(reference);
2000+
}
2001+
2002+
@Test // DATAMONGO-2328
2003+
public void mapsLongToDateWhenAnnotatedWithFieldTargetType() {
2004+
2005+
Date date = new Date();
2006+
WithExplicitTargetTypes source = new WithExplicitTargetTypes();
2007+
source.longAsDate = date.getTime();
2008+
2009+
org.bson.Document target = new org.bson.Document();
2010+
converter.write(source, target);
2011+
2012+
assertThat(target.get("longAsDate")).isEqualTo(date);
2013+
}
2014+
2015+
@Test // DATAMONGO-2328
2016+
public void readsDateAsLongWhenAnnotatedWithFieldTargetType() {
2017+
2018+
Date reference = new Date();
2019+
WithExplicitTargetTypes target = converter.read(WithExplicitTargetTypes.class,
2020+
new org.bson.Document("longAsDate", reference));
2021+
2022+
assertThat(target.longAsDate).isEqualTo(reference.getTime());
2023+
}
2024+
2025+
@Test // DATAMONGO-2328
2026+
public void mapsStringAsBooleanWhenAnnotatedWithFieldTargetType() {
2027+
2028+
WithExplicitTargetTypes source = new WithExplicitTargetTypes();
2029+
source.stringAsBoolean = "true";
2030+
2031+
org.bson.Document target = new org.bson.Document();
2032+
converter.write(source, target);
2033+
2034+
assertThat(target.get("stringAsBoolean")).isEqualTo(true);
2035+
}
2036+
2037+
@Test // DATAMONGO-2328
2038+
public void readsBooleanAsStringWhenAnnotatedWithFieldTargetType() {
2039+
2040+
WithExplicitTargetTypes target = converter.read(WithExplicitTargetTypes.class,
2041+
new org.bson.Document("stringAsBoolean", true));
2042+
2043+
assertThat(target.stringAsBoolean).isEqualTo("true");
2044+
}
2045+
2046+
@Test // DATAMONGO-2328
2047+
public void mapsDateAsObjectIdWhenAnnotatedWithFieldTargetType() {
2048+
2049+
WithExplicitTargetTypes source = new WithExplicitTargetTypes();
2050+
source.dateAsObjectId = new Date();
2051+
2052+
org.bson.Document target = new org.bson.Document();
2053+
converter.write(source, target);
2054+
2055+
// need to compare the the timestamp as ObjectId has an internal counter
2056+
assertThat(target.get("dateAsObjectId", ObjectId.class).getTimestamp())
2057+
.isEqualTo(new ObjectId(source.dateAsObjectId).getTimestamp());
2058+
}
2059+
2060+
@Test // DATAMONGO-2328
2061+
public void readsObjectIdAsDateWhenAnnotatedWithFieldTargetType() {
2062+
2063+
ObjectId reference = new ObjectId();
2064+
WithExplicitTargetTypes target = converter.read(WithExplicitTargetTypes.class,
2065+
new org.bson.Document("dateAsObjectId", reference));
2066+
2067+
assertThat(target.dateAsObjectId).isEqualTo(new Date(reference.getTimestamp()));
2068+
}
2069+
19712070
static class GenericType<T> {
19722071
T content;
19732072
}
@@ -1987,9 +2086,7 @@ void method() {}
19872086
},
19882087
SECOND {
19892088
@Override
1990-
void method() {
1991-
1992-
}
2089+
void method() {}
19932090
};
19942091

19952092
abstract void method();
@@ -2416,7 +2513,20 @@ static class WithExplicitTargetTypes {
24162513
@Field(targetType = FieldType.SCRIPT) //
24172514
List<String> scripts;
24182515

2419-
@Field(targetType = FieldType.DECIMAL128) BigDecimal bigDecimal;
2516+
@Field(targetType = FieldType.DECIMAL128) //
2517+
BigDecimal bigDecimal;
2518+
2519+
@Field(targetType = FieldType.INT64) //
2520+
Date dateAsLong;
2521+
2522+
@Field(targetType = FieldType.DATE_TIME) //
2523+
Long longAsDate;
2524+
2525+
@Field(targetType = FieldType.BOOLEAN) //
2526+
String stringAsBoolean;
2527+
2528+
@Field(targetType = FieldType.OBJECT_ID) //
2529+
Date dateAsObjectId;
24202530
}
24212531

24222532
}

0 commit comments

Comments
 (0)