spring-projects / spring-data-mongodb

Provides support to increase developer productivity in Java when using MongoDB. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
https://spring.io/projects/spring-data-mongodb/
Apache License 2.0
1.62k stars 1.09k forks source link

Improve exception message if type to read doesn't match declared type on Map value [DATAMONGO-1757] #2662

Closed spring-projects-issues closed 7 years ago

spring-projects-issues commented 7 years ago

Ivan Mushketyk opened DATAMONGO-1757 and commented

Spring data throws the following exception when reading data from a database:

org.springframework.data.mapping.model.MappingException: Couldn't find PersistentEntity for type java.lang.Long!
    at org.springframework.data.mapping.context.AbstractMappingContext.lambda$getRequiredPersistentEntity$2(AbstractMappingContext.java:239) ~[spring-data-commons-2.0.0.M4.jar:na]
    at java.util.Optional.orElseThrow(Optional.java:290) ~[na:1.8.0_131]
    at org.springframework.data.mapping.context.AbstractMappingContext.getRequiredPersistentEntity(AbstractMappingContext.java:239) ~[spring-data-commons-2.0.0.M4.jar:na]
    at org.springframework.data.mapping.context.AbstractMappingContext.getRequiredPersistentEntity(AbstractMappingContext.java:81) ~[spring-data-commons-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:235) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readMap(MappingMongoConverter.java:972) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:221) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1289) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$000(MappingMongoConverter.java:78) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.lambda$getPropertyValue$1(MappingMongoConverter.java:1237) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at java.util.Optional.map(Optional.java:215) ~[na:1.8.0_131]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1237) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getValueInternal(MappingMongoConverter.java:863) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.lambda$read$2(MappingMongoConverter.java:288) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:1.8.0_131]
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[na:1.8.0_131]
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[na:1.8.0_131]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_131]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:1.8.0_131]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:1.8.0_131]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_131]
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[na:1.8.0_131]
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:327) ~[spring-data-commons-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:277) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:235) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:191) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:187) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:78) ~[spring-data-mongodb-2.0.0.M4.jar:na]
    at org.springframework.data.mongodb.core.ReactiveMongoTemplate$ReadDocumentCallback.doWith(ReactiveMongoTemplate.java:2220) ~[spring-data-mongodb-2.0.0.M4.jar:na]

It stumbles on the following field:

@Document(collection = "snapshots")
public class Data implements Serializable {
    @Id
    private String snapshotId;
    // Some other fields ...

    // Causes the issue
    private Map<String, Long> files;
}

When the files field is removed everything works fine.

Data in MongoDB seems to match the type, here how this field looks in the database: !Screen Shot 2017-07-27 at 10.55.29.png|thumbnail!

Here are my Gradle dependencies:

dependencies {
    compile project(':cs-main-api-model')

    compile('org.springframework.boot:spring-boot-starter-webflux')
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb-reactive', version: '2.0.0.M2'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.0.0.M2'
    compile group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: '2.0.0.M2'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.M2'
}

UPDATE:

According to the Oliver's comment I've bumped up version of spring-boot to 2.0.0.M3, but I still see the same error. Here are my new dependencies:

compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb-reactive', version: '2.0.0.M3'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.0.0.M3'
compile group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: '2.0.0.M3'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.M3'

But it still results in a similar stack trace:

org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type java.lang.Long!
    at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:116) ~[spring-data-commons-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:244) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readMap(MappingMongoConverter.java:1029) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:230) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1368) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1316) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1259) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:71) ~[spring-data-commons-2.0.0.RC2.jar:na]
    at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:49) ~[spring-data-commons-2.0.0.RC2.jar:na]
    at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.extractInvocationArguments(ClassGeneratingEntityInstantiator.java:226) ~[spring-data-commons-2.0.0.RC2.jar:na]
    at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:200) ~[spring-data-commons-2.0.0.RC2.jar:na]
    at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:85) ~[spring-data-commons-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:264) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:244) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:200) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:196) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:86) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at org.springframework.data.mongodb.core.ReactiveMongoTemplate$ReadDocumentCallback.doWith(ReactiveMongoTemplate.java:2517) ~[spring-data-mongodb-2.0.0.RC2.jar:na]
    at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:100) ~[reactor-core-3.1.0.M3.jar:3.1.0.M3]

Affects: 2.0 RC2 (Kay)

Attachments:

Referenced from: commits https://github.com/spring-projects/spring-data-mongodb/commit/f2e72fe93188b496e4ca0f9456ccdbd1eef951f7, https://github.com/spring-projects/spring-data-mongodb/commit/c35ea14c4f2aa5de1677e5c71f9b31a19ba2c13a

spring-projects-issues commented 7 years ago

Oliver Drotbohm commented

You reported the issue against RC2, the stack trace however shows M4 to be used. We fixed a couple of glitches in that area in the RC2. Care to make sure you really run RC2 and see whether the problem still persists?

spring-projects-issues commented 7 years ago

Ivan Mushketyk commented

Hey Oliver,

Sorry, I've specified incorrect version in the issue, the stack trace is the source of truth in this case. I've added my Gradle dependencies in the issue's description

spring-projects-issues commented 7 years ago

Oliver Drotbohm commented

So it's just getting more puzzling. Boot 2.0 M2 uses Spring Data Kay M4. So we still don't know whether the issues persists on the most recent RC3. You should be able to just upgrade to Boot 2.0 M3 to get the latest bits to verify

spring-projects-issues commented 7 years ago

Ivan Mushketyk commented

I've bumped up the version of Boot to 2.0 M3, but I still get a very similar stack trace

spring-projects-issues commented 7 years ago

Oliver Drotbohm commented

Can you be more specific on "very similar"?

spring-projects-issues commented 7 years ago

Ivan Mushketyk commented

Same error message, different dependencies versions, slightly different chain of invocations

spring-projects-issues commented 7 years ago

Oliver Drotbohm commented

Judging from the stack trace you get Document instances returned for the value in the Map, not a Long value. I agree that we can throw a better exception for this explaining the mismatch, but that mismatch fundamentally seems to be caused by the data in your database not matching the object model in your code

spring-projects-issues commented 7 years ago

Ivan Mushketyk commented

Hey Oliver,

You are right, it was incorrect type in the model. Better exception would be really appreciated!

You can close this ticket

spring-projects-issues commented 7 years ago

Oliver Drotbohm commented

We now throw an exception with more context in the case you run into: we include the value that's supposed to be read as well as the type which we couldn't find a PersistentEntity for