Reputation: 1308
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
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