MongoDB ClassCastException with new GridFS API

Starting with the MongoDB Java API 3.1 a new GridFS API has been added. It is available under the com.mongodb.client.gridfs package.

If you are building a new application then the new GridFS API is the recommended one to use. However if you already have an existing system using the old GridFS API, then switching to the new API may result in you running an Exception that looks like this:

Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer
	at org.bson.Document.getInteger(Document.java:151)
	at com.mongodb.client.gridfs.GridFSFindIterableImpl$1.apply(GridFSFindIterableImpl.java:126)
	at com.mongodb.client.gridfs.GridFSFindIterableImpl$1.apply(GridFSFindIterableImpl.java:120)
	at com.mongodb.MappingIterable$1.apply(MappingIterable.java:53)
	at com.mongodb.OperationIterable.forEach(OperationIterable.java:73)
	at com.mongodb.FindIterableImpl.forEach(FindIterableImpl.java:150)
	at com.mongodb.MappingIterable.forEach(MappingIterable.java:50)
	at com.mongodb.client.gridfs.GridFSFindIterableImpl.forEach(GridFSFindIterableImpl.java:110)

This happens when your system is using the new GridFS API to access a file in the GridFS that was previously created with the old GridFS API. Also client tools such as MongoChef that allow you to manipulate a GridFS collection may internally be using the old GridFS API and could break your system that is using the new API.

You can test this with the source code below. The first Java class inserts a file into the GridFS using the new API:

import java.io.ByteArrayInputStream;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;

public class InsertNewGridFS {
    public static void main(String[] args) throws Throwable {
        MongoClient mongoClient = new MongoClient(
            new MongoClientURI("mongodb://localhost:27017"));
        MongoDatabase mongoDb = mongoClient.getDatabase("test");
        GridFSBucket gridFS = GridFSBuckets.create(mongoDb, "myfiles");
        gridFS.uploadFromStream(
            "hello1.txt",
            new ByteArrayInputStream("Hello world".getBytes("UTF-8"))
        );
        mongoClient.close();
    }
}

The second Java class inserts a file into the GridFS using the old API:

import java.io.ByteArrayInputStream;

import com.mongodb.MongoClient;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSInputFile;

public class InsertOldGridFS {
    public static void main(String[] args) throws Throwable {
        MongoClient client = new MongoClient("localhost", 27017);
        GridFS gridFS = new GridFS(client.getDB("test"), "myfiles");
        GridFSInputFile file = gridFS.createFile(
            new ByteArrayInputStream("Hello world".getBytes("UTF-8")),
            "hello2.txt"
        );
        file.save();
    }
}

The third Java class reads the entire GridFS collection using the old API and dumps the file names:

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;

public class ViewOldGridFS {
    public static void main(String[] args) throws Throwable {
        MongoClient client = new MongoClient("localhost", 27017);
        GridFS gridFS = new GridFS(client.getDB("test"), "myfiles");
        for (GridFSDBFile file : gridFS.find(new BasicDBObject())) {
            System.out.println(file.getFilename());
        }
    }
}

Finally the forth Java class does the same as the previous class but using the new GridFS API. This will result in the ClassCastException once it hits a file inserted with the old API:

import com.mongodb.Block;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.model.GridFSFile;

public class ViewNewGridFS {
    public static void main(String[] args) throws Throwable {
        MongoClient mongoClient = new MongoClient(
            new MongoClientURI("mongodb://localhost:27017"));
        MongoDatabase mongoDb = mongoClient.getDatabase("test");
        GridFSBucket gridFS = GridFSBuckets.create(mongoDb, "myfiles");
        gridFS.find().forEach(
            new Block<GridFSFile>() {
                @Override
                public void apply(final GridFSFile gridFSFile) {
                    System.out.println(gridFSFile.getFilename());
                }
            }
        );
        mongoClient.close();
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

*