I am experiencing a very strange problem. I am sending an object that has two lists (in my case, synchronized ArrayLists
) from a server to a client. One is a list of users connected to the server, and the other is a list of lobbies that exist on the server. Every lobby also has its own list of users that are connected to it. After creating the object that encapsulates all of these lists and their data on the server side, I walk through the user list and print out each user's username as well as the ID of the lobby they are currently in. I then send the object using an ObjectOutputStream
over a socket.
On the client side I receive the object using an ObjectInputStream
, cast it to my encapsulating object type, and then again walk through the user list, printing out each user's username and the ID of the lobby that they are in.
Here is where my problem occurs. Every user's username (and other data) is printed correctly, except the ID of the lobby that they are in. This is somehow null, even though the printing on the server side printed the IDs correctly.
Usernames are String
s, IDs are UUID
s, and users and lobbies each have their own respective class that I created.
I originally thought this could be some issue with passing by reference vs by value, or an issue with UUID
s, but even after changing IDs to be just a normal int, this still happens.
I then thought it could be my list structure. At the time I was using a ConcurrentHashMap
to store users and lobbies. I changed it to a synchronized list, but the same thing kept happening.
Note that when a new user connects, they receive a correct copy of the lists. But any lobbies that they or others join/leave are again not reflected correctly. Everything on the server side tracks and prints correctly though.
This is a relatively big project for me, and everything is rather connected, so I am unsure what code examples or output I should include. Please feel free to suggest anything that should be included/specified in my question, and I will add it. I'm still new to StackOverflow.
Any and all help is greatly appreciated!
EDIT: Here is a minimal reproducible example, sorry that it is so long.
Server.java
:
import java.io.IOException;
import java.net.ServerSocket;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class Server implements Runnable {
private final ServerSocket serverSocket;
private ConcurrentHashMap<UUID, User> users;
public Server(int port) throws IOException {
serverSocket = new ServerSocket(port);
users = new ConcurrentHashMap<>();
}
public ConcurrentHashMap<UUID, User> getUsers() {
return users;
}
public void addUser(User user) {
users.put(user.getId(), user);
}
private void setUserCurrentLobbyId(User user, UUID lobbyId) {
users.get(user.getId()).setCurrentLobbyId(lobbyId);
}
@Override
public void run() {
while (true) {
try {
(new Thread(new ClientHandler(this, serverSocket.accept()))).start();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) throws IOException, InterruptedException {
Server server = new Server(5050);
(new Thread(server)).start();
User user1 = new User("user1");
server.addUser(user1);
Thread.sleep(5000);
server.setUserCurrentLobbyId(user1, UUID.randomUUID());
}
}
ClientHandler.java
:
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class ClientHandler implements Runnable {
private final Server server;
private final Socket socket;
private ConcurrentHashMap<UUID, User> users;
public ClientHandler(Server server, Socket socket) {
this.server = server;
this.socket = socket;
users = new ConcurrentHashMap<>();
}
@Override
public void run() {
ObjectOutputStream out;
try {
out = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
while (true) {
updateMaps();
Response response = new Response(users);
System.out.println("Sent user list:");
for (Map.Entry<UUID, User> entry : response.users().entrySet()) {
System.out.println("\t" + entry.getValue().getUsername()
+ ", currentLobbyId: "
+ entry.getValue().getCurrentLobbyId());
}
try {
out.writeObject(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void updateMaps() {
this.users = new ConcurrentHashMap<>(server.getUsers());
}
}
Client.java
:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.Map;
import java.util.UUID;
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Socket socket = new Socket("localhost", 5050);
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
while (true) {
Response response = (Response) in.readObject();
System.out.println("Received user list:");
for (Map.Entry<UUID, User> entry : response.users().entrySet()) {
System.out.println("\t" + entry.getValue().getUsername()
+ ", currentLobbyId: "
+ entry.getValue().getCurrentLobbyId());
}
}
}
}
User.java
:
import java.io.Serializable;
import java.util.UUID;
public class User implements Serializable {
private final UUID id;
private final String username;
private int currentLobbyId;
public User(String username) {
this.id = UUID.randomUUID();
this.username = username;
}
public UUID getId() {
return id;
}
public String getUsername() {
return username;
}
public int getCurrentLobbyId() {
return currentLobbyId;
}
public void setCurrentLobbyId(int newLobbyId) {
currentLobbyId = newLobbyId;
}
}
Response.java
util class (I use this in my project as well, along with some added features that I have omitted here):
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public record Response(
ConcurrentHashMap<UUID, User> users)
implements Serializable {
}
To see the issue, run Server.java in one window and then Client.java in another, and compare their outputs. After 5 seconds a simulated lobby change happens. The sender prints the updated list correctly, but the receiver does not. Sorry if this MRE is a bit long, I wasn't too sure how far I could cut without removing important context.