Skip to content

Commit 8ca16e1

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-2315 - Fix $date parameter binding for string based queries.
Original pull request: #772.
1 parent 296e979 commit 8ca16e1

File tree

4 files changed

+81
-22
lines changed

4 files changed

+81
-22
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/DateTimeFormatter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ class DateTimeFormatter {
4545
static {
4646
FormatterImpl dateTimeHelper;
4747
try {
48-
dateTimeHelper = loadDateTimeFormatter("org.bson.json.DateTimeFormatter$Java8DateTimeFormatter");
48+
dateTimeHelper = loadDateTimeFormatter(
49+
"org.springframework.data.mongodb.util.json.DateTimeFormatter$Java8DateTimeFormatter");
4950
} catch (LinkageError e) {
5051
// this is expected if running on a release prior to Java 8: fallback to JAXB.
51-
dateTimeHelper = loadDateTimeFormatter("org.bson.json.DateTimeFormatter$JaxbDateTimeFormatter");
52+
dateTimeHelper = loadDateTimeFormatter(
53+
"org.springframework.data.mongodb.util.json.DateTimeFormatter$JaxbDateTimeFormatter");
5254
}
5355

5456
FORMATTER_IMPL = dateTimeHelper;

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingDocumentCodec.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.util.ArrayList;
2323
import java.util.Collection;
24+
import java.util.Date;
2425
import java.util.List;
2526
import java.util.Map;
2627
import java.util.UUID;
@@ -35,22 +36,13 @@
3536
import org.bson.BsonWriter;
3637
import org.bson.Document;
3738
import org.bson.Transformer;
38-
import org.bson.codecs.BsonTypeClassMap;
39-
import org.bson.codecs.BsonTypeCodecMap;
40-
import org.bson.codecs.BsonValueCodecProvider;
41-
import org.bson.codecs.Codec;
42-
import org.bson.codecs.CollectibleCodec;
43-
import org.bson.codecs.DecoderContext;
44-
import org.bson.codecs.DocumentCodecProvider;
45-
import org.bson.codecs.EncoderContext;
46-
import org.bson.codecs.IdGenerator;
47-
import org.bson.codecs.ObjectIdGenerator;
48-
import org.bson.codecs.ValueCodecProvider;
39+
import org.bson.codecs.*;
4940
import org.bson.codecs.configuration.CodecRegistry;
50-
5141
import org.springframework.data.spel.EvaluationContextProvider;
5242
import org.springframework.expression.spel.standard.SpelExpressionParser;
5343
import org.springframework.lang.Nullable;
44+
import org.springframework.util.NumberUtils;
45+
import org.springframework.util.ObjectUtils;
5446
import org.springframework.util.StringUtils;
5547

5648
/**
@@ -278,6 +270,17 @@ private Object readValue(final BsonReader reader, final DecoderContext decoderCo
278270
if (bindingReader.currentValue != null) {
279271

280272
Object value = bindingReader.currentValue;
273+
274+
if (ObjectUtils.nullSafeEquals(BsonType.DATE_TIME, bindingReader.getCurrentBsonType())
275+
&& !(value instanceof Date)) {
276+
277+
if (value instanceof Number) {
278+
value = new Date(NumberUtils.convertNumberToTargetClass((Number) value, Long.class));
279+
} else if (value instanceof String) {
280+
value = new Date(DateTimeFormatter.parse((String) value));
281+
}
282+
}
283+
281284
bindingReader.setState(State.TYPE);
282285
bindingReader.currentValue = null;
283286
return value;

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ private BindableValue bindableValueFor(JsonToken token) {
394394
matched = true;
395395
String group = matcher.group();
396396
int index = computeParameterIndex(group);
397-
computedValue = computedValue.replace(group, ObjectUtils.nullSafeToString(getBindableValueForIndex(index)));
397+
computedValue = computedValue.replace(group, nullSaveToString(getBindableValueForIndex(index)));
398398
}
399399

400400
if (!matched) {
@@ -406,7 +406,7 @@ private BindableValue bindableValueFor(JsonToken token) {
406406
String binding = regexMatcher.group();
407407
String expression = binding.substring(3, binding.length() - 1);
408408

409-
computedValue = computedValue.replace(binding, ObjectUtils.nullSafeToString(evaluateExpression(expression)));
409+
computedValue = computedValue.replace(binding, nullSaveToString(evaluateExpression(expression)));
410410
}
411411
}
412412

@@ -416,6 +416,15 @@ private BindableValue bindableValueFor(JsonToken token) {
416416
return bindableValue;
417417
}
418418

419+
private static String nullSaveToString(Object value) {
420+
421+
if (value instanceof Date) {
422+
return DateTimeFormatter.format(((Date) value).getTime());
423+
}
424+
425+
return ObjectUtils.nullSafeToString(value);
426+
}
427+
419428
private static int computeParameterIndex(String parameter) {
420429
return NumberUtils.parseNumber(parameter.replace("?", ""), Integer.class);
421430
}
@@ -1244,12 +1253,20 @@ private long visitDateTimeExtendedJson() {
12441253
} else {
12451254
if (valueToken.getType() == JsonTokenType.INT32 || valueToken.getType() == JsonTokenType.INT64) {
12461255
value = valueToken.getValue(Long.class);
1247-
} else if (valueToken.getType() == JsonTokenType.STRING) {
1248-
String dateTimeString = valueToken.getValue(String.class);
1249-
try {
1250-
value = DateTimeFormatter.parse(dateTimeString);
1251-
} catch (IllegalArgumentException e) {
1252-
throw new JsonParseException("Failed to parse string as a date", e);
1256+
} else if (valueToken.getType() == JsonTokenType.STRING
1257+
|| valueToken.getType() == JsonTokenType.UNQUOTED_STRING) {
1258+
1259+
Object dt = bindableValueFor(valueToken).getValue();
1260+
if (dt instanceof Date) {
1261+
value = ((Date) dt).getTime();
1262+
} else if (dt instanceof Number) {
1263+
value = NumberUtils.convertNumberToTargetClass((Number) dt, Long.class);
1264+
} else {
1265+
try {
1266+
value = DateTimeFormatter.parse(dt.toString());
1267+
} catch (IllegalArgumentException e) {
1268+
throw new JsonParseException(String.format("Failed to parse string '%s' as a date", dt), e);
1269+
}
12531270
}
12541271
} else {
12551272
throw new JsonParseException("JSON reader expected an integer or string but found '%s'.",

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.nio.charset.StandardCharsets;
2121
import java.util.Arrays;
2222
import java.util.Collections;
23+
import java.util.Date;
2324
import java.util.List;
2425

2526
import org.bson.Document;
@@ -158,6 +159,42 @@ public void bindSpEL() {
158159
assertThat(target).isEqualTo(new Document("arg0", 100.01D));
159160
}
160161

162+
@Test // DATAMONGO-2315
163+
public void bindDateAsDate() {
164+
165+
Date date = new Date();
166+
Document target = parse("{ 'end_date' : { $gte : { $date : ?0 } } }", date);
167+
168+
assertThat(target).isEqualTo(Document.parse("{ 'end_date' : { $gte : { $date : " + date.getTime() + " } } } "));
169+
}
170+
171+
@Test // DATAMONGO-2315
172+
public void bindQuotedDateAsDate() {
173+
174+
Date date = new Date();
175+
Document target = parse("{ 'end_date' : { $gte : { $date : '?0' } } }", date);
176+
177+
assertThat(target).isEqualTo(Document.parse("{ 'end_date' : { $gte : { $date : " + date.getTime() + " } } } "));
178+
}
179+
180+
@Test // DATAMONGO-2315
181+
public void bindStringAsDate() {
182+
183+
Date date = new Date();
184+
Document target = parse("{ 'end_date' : { $gte : { $date : ?0 } } }", "2019-07-04T12:19:23.000Z");
185+
186+
assertThat(target).isEqualTo(Document.parse("{ 'end_date' : { $gte : { $date : '2019-07-04T12:19:23.000Z' } } } "));
187+
}
188+
189+
@Test // DATAMONGO-2315
190+
public void bindNumberAsDate() {
191+
192+
Long time = new Date().getTime();
193+
Document target = parse("{ 'end_date' : { $gte : { $date : ?0 } } }", time);
194+
195+
assertThat(target).isEqualTo(Document.parse("{ 'end_date' : { $gte : { $date : " + time + " } } } "));
196+
}
197+
161198
private static Document parse(String json, Object... args) {
162199

163200
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, args);

0 commit comments

Comments
 (0)