简体   繁体   中英

No converter found capable of converting from type org.bson.BsonUndefined

I have mongo driver 3.2.2, spring data mongodb 1.9.1.RELEASE.

Collection:

{
  "_id": "5728a1a5abdb9c352cda6432",
  "isDeleted": null,
  "name": undefined
},
{
  "_id": "5728a1a5abdb9c352cda6433",
  "isDeleted": null,
  "name": null
}

When I try to fetch record with {"name":undefined} I get following exception.

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type org.bson.BsonUndefined to type java.lang.String
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleRead(MappingMongoConverter.java:821) ~[spring-data-mongodb-1.7.1.RELEASE.jar:?]

How to solve this? I have multiple types which needs to be converted from BsonUndefined like String, Date, PhoneNumber, etc...

I ran into this exact same problem on my code. I don't know why but for some reason the new mongo-java-drivers do not like having a "null" value at all in the data. If you notice that when you save an object and the value is null it actually doesn't even put the field in the document to start with.

We ended up having 1 collection that was written by a different "nodejs" application but being read by java. When we upgraded our mongo-java-driver to 3.2 version that particular collection started to break.

We ended up having to do an update on all the records in that collection similar to this

db.columnDefinition.update({field: null}, {$unset: {field: 1}}, {multi: true})

Once there were no records containing a "null" at all that was being mapped to a bean in the object, everything started working out just fine.

We did not have a single "undefined" in the collection but I can only guess that it will cause an issue as well.

And we were having the same BsonUndefined exception even though the problem had nothing to do with undefined.

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.bson.BsonUndefined] to type [java.lang.String]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313) ~[spring-core-4.3.1.RELEASE.jar:4.3.1.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-4.3.1.RELEASE.jar:4.3.1.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176) ~[spring-core-4.3.1.RELEASE.jar:4.3.1.RELEASE]

Edit: Also in our case we noticed that it didn't always seem to be a problem. We have other collections where we access them directly and they have "null" fields which are read in just fine. It seems to be related to anything that is being pulled in from a DBRef style. In my case the report had DBRef to column so reading the report broke because the column had a field that was null inside of it. But the report itself has fields that are null but does not break.

This is with spring-data 1.9.2, spring 4.3.1, mongo 3.2.2

We ran into this issue recently, so I'm putting the results of my research here in case someone else has this issue as well.

This is a known error in Spring Data MongoDB:

https://jira.spring.io/browse/DATAMONGO-1439

The workaround from that link is to add an explicit converter for converting from BsonUndefined to null . For example, using Java 8:

@ReadingConverter
public class BsonUndefinedToNullObjectConverterFactory implements ConverterFactory<BsonUndefined, Object> {
    @Override
    public <T extends Object> Converter<BsonUndefined, T> getConverter(Class<T> targetType) {
        return o -> null;
    }
}

Without the Lambda (pre-Java 8):

@ReadingConverter
public class BsonUndefinedToNullObjectConverterFactory implements ConverterFactory<BsonUndefined, Object> {

    @Override
    public <T extends Object> Converter<BsonUndefined, T> getConverter(Class<T> targetType) {
        return new Converter<BsonUndefined, T>() {
            @Override
            public T convert(BsonUndefined source) {
                return null;
            }
        };
    }
}

For Java it does not really matter whether the field exists or has a null value so you could also replace it just bu null like in the answer above. However if you really want to match the fields that have the exact "undefined" value you can only do it in JS in Mongo console.

In my case I wanted to remove all of such fields from the object so the function doing both the proper check and remove would look like:

function unsetUndefined(obj) {
    return Object.keys(obj).filter((k, i) => {
        if(obj[k] === undefined) {
            delete obj[k];
            return true
        }
        return false;
    }).length > 0;
}

Later combining it all together into executable Mongo Shell code it could be something like:

const collectionName = "...";
const query = {...};

function unsetUndefined(obj) {
    return Object.keys(obj).some((k, i) => {
        if(obj[k] === undefined) {
            delete obj[k];
            return true;
        }
    });
}

db.getCollection(collectionName).find(query).forEach(record =>{
    const changed =  unsetUndefined(record);
    if(changed) {
        db.getCollection(collectionName).save(record);
    }
});

If undefined values are unwanted (ie were created due to some error) - you can unset them, by running following mongo script:

var TYPE_UNDEFINED = 6;
db.getCollection("my.lovely.collection").updateMany({ "name": {$type: TYPE_UNDEFINED}}, {
    $unset: {"name": 1}
});

or set them to null - if that's preferred solution:

var TYPE_UNDEFINED = 6;
db.getCollection("my.lovely.collection").updateMany({ "name": {$type: TYPE_UNDEFINED}}, {
    $set: {"name": null}
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM