I have a Java game that uses networking, and I have a client (using a Socket) fetching objects from an ObjectInputStream, running in its own thread.
From Client.java:
Object input = null;
while(true) {
input = in.readObject();
if(input != null) {
listener.gotObject(input);
}
}
This works pretty well. The object is gotten and is passed to the listener, which is a class linked to a my main GameApp class.
From the listener (NetControl.java):
public void gotObject(Object o) {
System.out.println(o);
app.gotObject(o);
}
"app" is the instance that handles all new objects received and deals with them.
From the app (GameApp.java) (edit: the non-abstract CardGameApp.java gives greater context):
public void gotObject(Object o) {
// select instance:
if(o instanceof GameList) {
GameList gameList = (GameList) o;
System.out.println("gamelist: " + gameList);
this.lobbyControl.gotGameList(gameList);
}
}
I've run this code in the debugger, one step at a time, and it works perfectly. When I run it normally though, I get a null pointer (output is as follows:)
Game ID: 0. Name: game1. Players: 1 / 1. // the object, as it is printed in Client.java
gamelist: Game ID: 0. Name: game1. Players: 1 / 1. // the object, as it is printed again in GameApp.java
Exception in thread "Thread-1" java.lang.NullPointerException
at com.lgposse.game.app.GameApp.gotObject(GameApp.java:61)
at com.lgposse.game.net.NetControl.gotObject(NetControl.java:47)
at com.lgposse.net.client.Client.run(Client.java:49)
Now, I see the object being printed twice, so I know it has been received... but I get a null pointer.
I added a sleep function in the middle of the function:
else if(o instanceof GameList) {
GameList gameList = (GameList) o;
System.out.println("gamelist: " + gameList);
try {
Thread.sleep(1000); // sleep 100 still gave null pointer
} catch (InterruptedException e) {}
this.lobbyControl.gotGameList(gameList);
}
And setting it to sleep for a while, it all finally worked.
Any idea why I need to sleep the thread like this? Is there something I should do differently? I'm not sure why I was able to print the object while it was still considered null.
Edit: added some more context.
It looks like lobbyControl
is null
, not gameList
. If gameList
were null, the top of the stack would be the gotGameList()
method, not gotObject()
.
If sleeping helps the problem, then you must be manipulating the lobbyControl
member without proper concurrency safeguards. An ObjectInputStream
won't return an object until it's been fully read from the stream, so your problem has nothing to do with not having completely read the object.
Update: I can't follow all the code, but it appears that a reference to the object being constructed is leaked to a thread (the client
in the NetControl
), which is started before the constructor completes. If that is the case, that's very, very bad. You should never allow a partially constructed object to become visible to another thread.