[JAVA-605] NullPointerException on DBCursor.hasNext() when cursor is closed Created: 18/Jul/12  Updated: 19/Oct/16  Resolved: 30/Jan/14

Status: Closed
Project: Java Driver
Component/s: API
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Sushil Thampy Assignee: Jeffrey Yemin
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Linux Ubuntu 11.04, mongod 2.0.5


Issue Links:
Related
related to JAVA-1091 Always set awaitData along with taila... Closed

 Description   

When iterating over a DBCursor using standard hasNext()/next() logic, hasNext() can raise a NullPointerException when the underlying server-side cursor has been closed. This happens in my code because I wrap the DBCursor in another Iterator that provides "batching": Iterates over the DBCursor generating a list of objects instead of a single object.

I has been able to trace the issue to the following code fragments in DBApiLayer:

public boolean hasNext(){
    boolean hasNext = _cur.hasNext();
    while ( !hasNext ) {
      ....
    }
    return hasNext;
}
...
void close(){
    if (_curResult != null) {
        killCursor();
        _curResult = null;
        _cur = null;
    }
}

Please the documentation tells the hasNext() method can throw a MongoException and there are some issues that deal with this API issue.



 Comments   
Comment by Jeffrey Yemin [ 30/Jan/14 ]

Fixed in scope of JAVA-1091 changes

Comment by Jeffrey Yemin [ 24/Jan/14 ]

lllegalStateException is the more correct exception to throw here. InterruptedException has a pretty specific meaning that does not seem to apply here.

Comment by raulvk [ 08/Jul/13 ]

I suggested borrowing InterruptedException due to the multi-threading aspect of this problem.

This NPE only happens when the DBCursor is closed from another thread while it's blocked waiting for results. From a logical standpoint, I equate this situation to an interruption of Thread.sleep(), which throws an InterruptedException.

I would argue against a generic MongoException, because that can mean anything and could potentially trigger client logic to regenerate the cursor. Especially in this context given that, AFAIR, MongoDB reserves its right to close a tailable cursor server-side. So more likely than not, nicely programmed clients would have implemented regeneration logic.

Perhaps a MongoException.CursorClosedException would work, if you'd rather not use a standard JDK exception?

Comment by Jeffrey Yemin [ 08/Jul/13 ]

I agree about the NPE, but what's the precedent for InterruptedException? Calling Socket.close(), for example, doesn't result in pending reads throwing InterruptedException. You just get a generic SocketException. Similarly, I would argue for a generic MongoException in this case.

Comment by raulvk [ 07/Jul/13 ]

I'm a committer in the Apache Camel project, and I've come across this NPE when upgrading from 2.9.1 to 2.11.2.

I see this exception from the Java driver when stopping a Camel route that was consuming from a MongoDB tailable cursor (camel-mongodb component) and was blocked at DBCursor#hasNext.

IMHO, a NPE is a sign that the developer forgot to handle a situation gracefully (!). Furthermore, this NPE is not part of the contract of the DBCursor#hasNext method.

Can 10gen improve the driver to detect this case and throw a standard InterruptedException instead? The latter is self-explanatory and accurate for this case. It's extremely inelegant for us to have to catch a NPE

Comment by Jeffrey Yemin [ 27/Aug/12 ]

It does seem to be the case that if you call DBCursor.hasNext() after calling DBCursor.close(), it will throw an NPE. But I don't quite see why this is a problem in practice, except that maybe it should throw a different exception type.

Generated at Thu Feb 08 08:52:40 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.