Skip to content

Commit e2d901f

Browse files
committed
DATAMONGO-2511 Give context to mapping exceptions
When invoking findAll() exception details contained no information which document was malformed and other details (for example which field was wrong) were usually useless for identifying the document. Now the mapping exception will include the document.
1 parent c217618 commit e2d901f

File tree

3 files changed

+51
-15
lines changed

3 files changed

+51
-15
lines changed

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.springframework.context.ApplicationContext;
4444
import org.springframework.context.ApplicationContextAware;
4545
import org.springframework.core.CollectionFactory;
46+
import org.springframework.core.convert.ConversionException;
4647
import org.springframework.core.convert.ConversionService;
4748
import org.springframework.core.convert.support.DefaultConversionService;
4849
import org.springframework.data.annotation.Reference;
@@ -54,15 +55,7 @@
5455
import org.springframework.data.mapping.PreferredConstructor.Parameter;
5556
import org.springframework.data.mapping.callback.EntityCallbacks;
5657
import org.springframework.data.mapping.context.MappingContext;
57-
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
58-
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
59-
import org.springframework.data.mapping.model.EntityInstantiator;
60-
import org.springframework.data.mapping.model.ParameterValueProvider;
61-
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
62-
import org.springframework.data.mapping.model.PropertyValueProvider;
63-
import org.springframework.data.mapping.model.SpELContext;
64-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
65-
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
58+
import org.springframework.data.mapping.model.*;
6659
import org.springframework.data.mongodb.CodecRegistryProvider;
6760
import org.springframework.data.mongodb.MongoDatabaseFactory;
6861
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty;
@@ -104,11 +97,13 @@
10497
* @author Roman Puchkovskiy
10598
* @author Heesu Jung
10699
* @author Divya Srivastava
100+
* @author Piotr Kubowicz
107101
*/
108102
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
109103

110104
private static final String INCOMPATIBLE_TYPES = "Cannot convert %1$s of type %2$s into an instance of %3$s! Implement a custom Converter<%2$s, %3$s> and register it with the CustomConversions. Parent object was: %4$s";
111105
private static final String INVALID_TYPE_TO_READ = "Expected to read Document %s into type %s but didn't find a PersistentEntity for the latter!";
106+
private static final String CANNOT_READ = "Failed to read %s";
112107

113108
public static final ClassTypeInformation<Bson> BSON = ClassTypeInformation.from(Bson.class);
114109

@@ -350,7 +345,11 @@ protected <S extends Object> S readDocument(ConversionContext context, Bson bson
350345
throw new MappingException(String.format(INVALID_TYPE_TO_READ, document, rawType));
351346
}
352347

353-
return read(context, (MongoPersistentEntity<S>) entity, document);
348+
try {
349+
return read(context, (MongoPersistentEntity<S>) entity, document);
350+
} catch (ConversionException | MappingInstantiationException e) {
351+
throw new MappingException(String.format(CANNOT_READ, document), e);
352+
}
354353
}
355354

356355
private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(ConversionContext context,

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import lombok.AllArgsConstructor;
2424
import lombok.Data;
2525
import lombok.NoArgsConstructor;
26+
import lombok.NonNull;
27+
import lombok.Value;
2628

2729
import java.time.Instant;
2830
import java.time.LocalDate;
@@ -55,6 +57,7 @@
5557
* Integration tests for {@link MappingMongoConverter}.
5658
*
5759
* @author Christoph Strobl
60+
* @author Piotr Kubowicz
5861
*/
5962
@ExtendWith(MongoClientExtension.class)
6063
public class MappingMongoConverterTests {
@@ -76,12 +79,13 @@ void setUp() {
7679

7780
database.getCollection("samples").deleteMany(new Document());
7881
database.getCollection("java-time-types").deleteMany(new Document());
82+
database.getCollection("with-nonnull").deleteMany(new Document());
7983

8084
dbRefResolver = spy(new DefaultDbRefResolver(factory));
8185

8286
mappingContext = new MongoMappingContext();
8387
mappingContext.setInitialEntitySet(new HashSet<>(
84-
Arrays.asList(WithLazyDBRefAsConstructorArg.class, WithLazyDBRef.class, WithJavaTimeTypes.class)));
88+
Arrays.asList(WithLazyDBRefAsConstructorArg.class, WithLazyDBRef.class, WithJavaTimeTypes.class, WithNonnullField.class)));
8589
mappingContext.setAutoIndexCreation(false);
8690
mappingContext.afterPropertiesSet();
8791

@@ -145,6 +149,31 @@ void readJavaTimeValuesWrittenViaCodec() {
145149
.isEqualTo(source);
146150
}
147151

152+
@Test // DATAMONGO-2511
153+
public void reportConversionFailedExceptionContext() {
154+
155+
configureConverterWithNativeJavaTimeCodec();
156+
MongoCollection<Document> mongoCollection = client.getDatabase(DATABASE).getCollection("java-time-types");
157+
158+
mongoCollection.insertOne(new Document("_id", "id-of-wrong-document").append("localDate", "not-a-date"));
159+
160+
assertThatThrownBy(() -> converter.read(WithJavaTimeTypes.class,
161+
mongoCollection.find(new Document("_id", "id-of-wrong-document")).first()))
162+
.hasMessageContaining("id-of-wrong-document");
163+
}
164+
165+
@Test // DATAMONGO-2511
166+
public void reportMappingInstantiationExceptionContext() {
167+
168+
MongoCollection<Document> mongoCollection = client.getDatabase(DATABASE).getCollection("with-nonnull");
169+
170+
mongoCollection.insertOne(new Document("_id", "id-of-wrong-document"));
171+
172+
assertThatThrownBy(() -> converter.read(WithNonnullField.class,
173+
mongoCollection.find(new Document("_id", "id-of-wrong-document")).first()))
174+
.hasMessageContaining("id-of-wrong-document");
175+
}
176+
148177
void configureConverterWithNativeJavaTimeCodec() {
149178

150179
converter = new MappingMongoConverter(dbRefResolver, mappingContext);
@@ -212,4 +241,10 @@ Document toDocument() {
212241
.append("localDateTime", localDateTime);
213242
}
214243
}
244+
245+
@Value
246+
static class WithNonnullField {
247+
@Id String id;
248+
@NonNull String field;
249+
}
215250
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -856,8 +856,9 @@ void rejectsNotFoundConstructorParameterForPrimitiveType() {
856856

857857
org.bson.Document document = new org.bson.Document("foo", "bar");
858858

859-
assertThatThrownBy(() -> converter.read(DefaultedConstructorArgument.class, document))
860-
.isInstanceOf(MappingInstantiationException.class);
859+
assertThatThrownBy(() -> converter.read(DefaultedConstructorArgument.class, document)) //
860+
.isInstanceOf(MappingException.class) //
861+
.hasCauseInstanceOf(MappingInstantiationException.class);
861862
}
862863

863864
@Test // DATAMONGO-358
@@ -1855,8 +1856,9 @@ void rejectsConversionFromStringToEnumBackedInterface() {
18551856

18561857
org.bson.Document document = new org.bson.Document("property", InterfacedEnum.INSTANCE.name());
18571858

1858-
assertThatExceptionOfType(ConverterNotFoundException.class) //
1859-
.isThrownBy(() -> converter.read(DocWithInterfacedEnum.class, document));
1859+
assertThatThrownBy(() -> converter.read(DocWithInterfacedEnum.class, document)) //
1860+
.isInstanceOf(MappingException.class) //
1861+
.hasCauseInstanceOf(ConverterNotFoundException.class);
18601862
}
18611863

18621864
@Test // DATAMONGO-1898

0 commit comments

Comments
 (0)