RMI NotSerializableException although it's a remote object
Asked Answered
R

3

11

I'm writing a small RMI based Chat application.

The idea is: the Client registers himself on the Server, and everytime the server receives a message from a client, he pushes this message to all other clients.

But I receive a NotSerializableException although, the object, I'm passing as a method parameter implements the Remote interface.

Here is some code: (The problematic part is the this parameter in this.chatServ.registriereClient(this); (ClientChat Implementation))

The (ClientChat)interface:

public interface ChatClient extends Remote
{

}

(ClientChat)Implementation:

public class ChatClientImpl implements ChatClient
{

    ChatServer chatServ;
    String clientName;

    public ChatClientImpl(String clientName, ChatServer chatServ) {
        this.chatServ = chatServ;
        this.clientName = clientName;
        try {
            this.chatServ.registriereClient(this);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

(ServerChat) Interface

public interface ChatServer extends Remote
{
        void registriereClient(ChatClient client) throws RemoteException;

}

(ServerChat) Implementation

public class LobbyChatServerImpl implements ChatServer
{

    ArrayList<ChatClient> clientListe = null;

    @Override
    public void registriereClient(ChatClient client) {
        System.out.println("Client registriert");
        this.clientListe.add(client);
    }
}

Client:

  public static void main(String[] args) {
        ChatServer lobbyChatServer = null;
        try {
            Registry registry = LocateRegistry.getRegistry(Server.RMI_PORT);
            lobbyChatServer = (ChatServer) registry.lookup("LobbyChatServer");

        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (NotBoundException e) {
            e.printStackTrace();
        }

        ChatClient lobbyChat = new ChatClientImpl(name, lobbyChatServer);
  }

Server:

    public static void main(String[] args) {
        try {
            if (System.getSecurityManager() == null) {
                System.setSecurityManager(new RMISecurityManager());
            }

            Registry registry = LocateRegistry.getRegistry(RMI_PORT);

            ChatServer lobbyChatStub = (ChatServer)UnicastRemoteObject.exportObject(new LobbyChatServerImpl(), 0);
            registry.bind("LobbyChatServer", lobbyChatStub);

        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (AlreadyBoundException e) {
            e.printStackTrace();
        }
    }

Exception:

java.rmi.MarshalException: error marshalling arguments; nested exception is: 
    java.io.NotSerializableException: de.XX.Chat.ChatClientImpl
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:156)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
    at $Proxy0.registriereClient(Unknown Source)
    at de.XX.Chat.ChatClientImpl.<init>(ChatClientImpl.java:19)
    at de.XX.Client.main(Client.java:49)
Caused by: java.io.NotSerializableException: de.XX.Chat.ChatClientImpl
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:292)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:151)
    ... 5 more

As already said, I wonder why i get this kind of Exception, although ChatClientImpl is already Remote.

Hope you can help me:)

Runofthemine answered 15/6, 2012 at 11:26 Comment(0)
D
18

Objects passed as parameters or results of remote methods must be either:

  1. Serializable (or Externalizable), or

  2. Exported remote objects.

Yours is neither. However as it implements a Remote interface clearly you intended (2). Objects that extend UnicastRemoteObject are auto-exported on construction. Objects that don't must be exported explicitly, via UnicastRemoteObject.exportObject().

Deary answered 15/6, 2012 at 11:49 Comment(0)
L
1

What you can do is setup a callback object. This is one which extends UnicastRemoteObject and when you pass this it becomes a callback.

http://www.cs.swan.ac.uk/~csneal/InternetComputing/RMIChat.html


Remote is not Serializable. You can't pass a proxy object this way. Even if you made it Serializable it would send a copy of the object which would exist on the server. The copy of the object on the client would not be called.

For your "server" to send messages to your "client" you have to create a service on the "client" to make it a server.

You may find that using a messaging solution such as JMS is better suited to this take. A JMS server has topics which you can publish to and subscribe from. A simple JMS server to use is Active MQ.

Latency answered 15/6, 2012 at 11:30 Comment(3)
so, if I understand you right, I cannot pass an remote object via a parameter to the server and let the server call other methods on this passed object?Runofthemine
You can, but the object called will be on the server. You can't have it call the client from the server this way. There are some RPC protocols which support this, but I don't rememeber which (I have written one in the past ;). For a chat server, JMS Topics is the simplest way to do this.Latency
It doesn't have to extend UnicastRemoteObject: you can export it manually.Deary
T
1

Looks like you might have forgotten to 'extends UnicastRemoteObject' on the interface implementations:

public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{
} 

and

public class LobbyChatServerImpl extends UnicastRemoteObject  implements ChatServer{
}
Toluidine answered 21/12, 2014 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.