gdoubleod
gdoubleod

Reputation: 1308

Java Driver throws null pointer on cursor.hasNext()

Java Driver throws null pointer exception on cursor.hasNext()

_collection  = db.getCollection("users");
DBCursor cursor = _collection.find();
System.out.println( "cursor len " + cursor.size() );
//outputs: "cursor len 2"

try {
   while(cursor.hasNext()) { //Throws null pointer exception
       System.out.println(cursor.next());
   }
} finally {
       cursor.close();
}

mongo shell:
db.users.find()
{ "_id" : ObjectId("51be2534036412d6b648354b"), "name" : "dude" }
{ "_id" : ObjectId("51be4de19234ec062efe4a53"), "name" : "lewbowski" }

why?? :(

Stack trace:

Jun 16, 2013 5:28:36 PM com.mongodb.DBPortPool gotError
WARNING: emptying DBPortPool to localhost/127.0.0.1:27017 b/c of error
java.lang.NullPointerException
at org.v2d2.data.UserDAO.put(UserDAO.java:166)
at org.bson.BasicBSONCallback._put(BasicBSONCallback.java:174)
at org.bson.BasicBSONCallback.gotObjectId(BasicBSONCallback.java:143)
at org.bson.BasicBSONDecoder.decodeElement(BasicBSONDecoder.java:160)
at org.bson.BasicBSONDecoder._decode(BasicBSONDecoder.java:79)
at org.bson.BasicBSONDecoder.decode(BasicBSONDecoder.java:57)
at com.mongodb.DefaultDBDecoder.decode(DefaultDBDecoder.java:61)
at com.mongodb.Response.<init>(Response.java:83)
at com.mongodb.DBPort.go(DBPort.java:142)
at com.mongodb.DBPort.call(DBPort.java:92)
at com.mongodb.DBTCPConnector.innerCall(DBTCPConnector.java:244)
at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:216)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:288)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:273)
at com.mongodb.DBCursor._check(DBCursor.java:368)
at com.mongodb.DBCursor._hasNext(DBCursor.java:459)
at com.mongodb.DBCursor.hasNext(DBCursor.java:484)
at org.v2d2.data.UserDAO.<init>(UserDAO.java:76)
at MongoTest.main(MongoTest.java:41)

===========================================================

I fixed the null pointer but I am no closer. When I try to get the values out of the class they are returning null.

public class UserDAO implements DBObject {

private String _name;
private String _id;

private ArrayList<String> _buildServers;
private BasicDBObject _dao;
private DBCollection _collection;


public UserDAO() {  }

public UserDAO(
        String name,
        DB db )
{
    _name     = name;
    _dao      = new BasicDBObject();

    _collection  = db.getCollection("users");


    _dao.put( "name", _name);

    DBCursor cursor = _collection.find();

    System.out.println( "curso len " + cursor.count() );
    try {
       while(cursor.hasNext()) {
           System.out.println( ((UserDAO)cursor.next()).GetName() );
       }
    } finally {
            cursor.close();
    }
}

public void SetName( String value )
{
    _name = value;
}

public String GetName()
{
    return _name;
}

@Override
public boolean containsField(String arg0)
{
    return _dao.containsField( arg0 );
}

@Override
@Deprecated
public boolean containsKey(String arg0)
{
    return _dao.containsKey( arg0 );
}

@Override
public Object get(String arg0)
{
    return _dao.get( arg0 );
}

@Override
public Set<String> keySet()
{
    return _dao.keySet();
}

@Override
public Object put(String arg0, Object arg1)
{
            //Error was being thrown in here added null check but I can't set the values
    if( _dao == null ) _dao = new BasicDBObject();
    return _dao.put( arg0, arg1 );
}

@Override
public void putAll(BSONObject arg0)
{
    // TODO Auto-generated method stub
    _dao.putAll( arg0 );
}

@Override
public void putAll(Map arg0)
{
    // TODO Auto-generated method stub
    _dao.putAll( arg0 );
}

@Override
public Object removeField(String arg0)
{
    // TODO Auto-generated method stub
    return _dao.removeField( arg0 );
}

@Override
public Map toMap()
{
    return _dao.toMap();
}

@Override
public boolean isPartialObject()
{
    // TODO Auto-generated method stub
    return _dao.isPartialObject();
}

@Override
public void markAsPartialObject()
{
    // TODO Auto-generated method stub
    _dao.markAsPartialObject();
}

}

Upvotes: 0

Views: 2227

Answers (1)

Trisha
Trisha

Reputation: 3931

The error you're getting is in

public Object put(String arg0, Object arg1)
{
    //Error was being thrown in here added null check but I can't set the values
    if( _dao == null ) _dao = new BasicDBObject();
    return _dao.put( arg0, arg1 );
}

as you've pointed out.

This is because this method is being called by the driver itself when you're retrieving items from the database.

So you do some sort of find() on your collection, and the driver recognises that it needs to create a new UserDAO object for the values being returned from that find(). It will create a brand new UserDAO object (using the default constructor, the one that takes no arguments) and then call put() to set the appropriate values from the database on your new UserDAO object.

Because the object was a shiny new one create using the default no-args constructor, at this point your _dao field was null and empty. You are correctly dealing with this by doing a null check and creating a new one if required. However, this does mean that all the other fields you set up in the other constructor (the one that takes a name and a DB) are not initialised, because that constructor was never called.

If all the fields need to be initialised for all new objects, you need to create a common initialisation method that can be called where you are currently creating the new BasicDBObject for the _dao field. However, you're going to have trouble with this as you will not know what the DB field (for example) should be.

Basically the problem is that your UserDAO should not have a reference to the DB it comes from. I know that sounds contrary to what a DAO does, but that's because using MongoDB via Java does not follow the same sort of patterns as using a SQL database with JDBC. The DAO pattern is not really suitable in this case.

Upvotes: 1

Related Questions