Results 1 to 19 of 19
  1. #1
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Returning a custom Object via RMI

    Hey!

    I just started using RMI, where I want to simualte a server from which my program gets different values. It`s pretty easy for simple return types like strings, integers or lists.
    but now I need to create and return a custom Object from the server to the client.

    I want to put two values (as a custom Object "valuepair") into a Hashmap together wit a key. For example like this: "signals.put("Temperature", valuepair)".

    What I'm struggling is, where to put the class ValuePair. I have three packages. The client, an interface, and the server.
    The client needs to get the Hashmap from the server.

    This is what I have right now:

    The Interface package:
    Java Code:
    package rmiinterface;
    package rmiinterface;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    import java.util.Map;
    
    public interface RMI extends Remote{
    
      public Map<String, rmiinterface.ValuePair> getAllSignals(String VIN) throws RemoteException;
         
    }
    And in this package I also implemented my custom class, since the client, and the server both need to know how the object is build:
    Java Code:
    package rmiinterface;
    
    import java.rmi.Remote;
    
    public class ValuePair implements Remote {
        final int timestamp;
        final double value;
        
        public ValuePair(){
            this.timestamp = 1000;
            this.value = 75.0;
        }
    }
    The server package has following method in it (this is where i actually want to manipulate the values). But here is what I don't understand.
    If my object would be a class of the server package I could set a value, e.g. the timestamp with: Valuepair.timestamp = 80.0, but I can't do this with riminterface.ValuePair.timestamp = 80.0.
    So do I have to implement the custom class in the server package? And if so, then how do I tell the client how this object looks like?
    Java Code:
    @Override
      public Map<String, rmiinterface.ValuePair> getAllSignals(String VIN) throws RemoteException{
      
      rmiinterface.ValuePair valuepair = new rmiinterface.ValuePair();
      System.out.println("Valuepair is: " + valuepair); 
      HashMap<String, rmiinterface.ValuePair> signals = new HashMap<String, rmiinterface.ValuePair>();
      signals.put("Temperarute", valuepair);
      return signals;
      }
    My client connects to the server like this:
    Java Code:
     public static Map<String, rmiinterface.ValuePair> getAllSignals(String vin) throws RemoteException{
            RMI rmi = RMIConnect();
            Map<String, rmiinterface.ValuePair> signals = rmi.getAllSignals(vin);
            return (Map<String, rmiinterface.ValuePair>) signals;   
           }
    And here I'm calling the method to connect to the server (here I want to display the returned Signal from the server). But this code causes an error message, so it's not executable.
    Java Code:
     @Override
        public void initialize(URL url, ResourceBundle rb) {
          
                try {
    
                    HashMap<String, rmiinterface.ValuePair> signals = new HashMap<>();
                    signals = (HashMap<String, ValuePair>) ServerConnection.getAllSignals("1234");
                    System.out.println(signals);
                   
          
                } catch (RemoteException ex) {
                    Logger.getLogger(VehicleSelectionController.class.getName()).log(Level.SEVERE, null, ex);
                }
        }
    Thanks in advance for any explanations!

  2. #2
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    Eastern Florida
    Posts
    20,003
    Rep Power
    33

    Default Re: Returning a custom Object via RMI

    this code causes an error message
    Please copy the full text of the error message and paste it here. It has important info about the error.

    I don't use RMI, but I'm sure the full text of the error message will help anyone that does.
    If you don't understand my response, don't ignore it, ask a question.

  3. #3
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Quote Originally Posted by Norm View Post
    Please copy the full text of the error message and paste it here. It has important info about the error.

    I don't use RMI, but I'm sure the full text of the error message will help anyone that does.
    Sorry, the error message looks like this:

    Java Code:
    java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
    	java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: rmiinterface.ValuePair
    	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:193)
    	at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:227)
    	at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:179)
    	at com.sun.proxy.$Proxy5.getAllSignals(Unknown Source)
    	at Test.ServerConnection.getAllSignals(ServerConnection.java:84)
    	at Test.VehicleSelectionController.initialize(VehicleSelectionController.java:90)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
    	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
    	at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
    	at Test.ServerConnection.start(ServerConnection.java:32)
    	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    	at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    	at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    	at java.lang.Thread.run(Thread.java:745)
    Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: rmiinterface.ValuePair
    	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1357)
    	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
    	at java.util.HashMap.readObject(HashMap.java:1396)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1058)
    	at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1909)
    	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1808)
    	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
    	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
    	at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:326)
    	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:175)
    	... 23 more
    Caused by: java.io.NotSerializableException: rmiinterface.ValuePair
    	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    	at java.util.HashMap.internalWriteEntries(HashMap.java:1777)
    	at java.util.HashMap.writeObject(HashMap.java:1354)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1028)
    	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    	at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:294)
    	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:334)
    	at sun.rmi.transport.Transport$1.run(Transport.java:200)
    	at sun.rmi.transport.Transport$1.run(Transport.java:197)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    	... 1 more

  4. #4
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    Eastern Florida
    Posts
    20,003
    Rep Power
    33

    Default Re: Returning a custom Object via RMI

    java.io.NotSerializableException: rmiinterface.ValueP
    Look up the API doc for Class NotSerializableException. The ValueP class should implement Serializable.
    If you don't understand my response, don't ignore it, ask a question.

  5. #5
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Quote Originally Posted by Norm View Post
    Look up the API doc for Class NotSerializableException. The ValueP class should implement Serializable.
    Thanks for that tip!
    It's executable now without an error. As you said, the class just has to implement Serializable:

    Java Code:
    public class ValuePair implements Remote, java.io.Serializable {
        final int timestamp;
        final double value;
         
        public ValuePair(){
            this.timestamp = 1000;
            this.value = 75.0;
        }
    }

  6. #6
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    But one question remains now.
    I want to set the ValuePair in my Server method getAllSignals().
    So I changed the variables temperature and value in class ValuePair from final to public, to access them in my Server method.
    That works now.

    The only thing I don't know is how to access the values on client side.

    The code
    Java Code:
                    signals = (HashMap<String, ValuePair>) ServerConnection.getAllSignals("1234");
                    System.out.println(signals);
    gives me the Output:
    {Temperature=rmiinterface.ValuePair@44500dff}

    with "Temperature" as my HashMap Key. But how do I access the ValuePair variables "temperature" and "value"?
    Let's say I want to split the three HashMap items into three independent variables.

  7. #7
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    13,541
    Rep Power
    27

    Default Re: Returning a custom Object via RMI

    1. Don't expose variables directly by making them public. Use getters and setters instead.
    2. You need to override the toString method to return a String in the format you want to display. Currently your ValuePair class is using the default (Object) toString which prints the class name and hashcode.
    Please do not ask for code as refusal often offends.

    ** This space for rent **

  8. #8
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Thank you!
    I created getters and setters, and override the toString method. My ValuePair class looks like this now:
    Java Code:
    package rmiinterface;
    
    import java.rmi.Remote;
    
    public class ValuePair implements Remote, java.io.Serializable {
          int timestamp;
          double value;
        
        public ValuePair(){
           this.timestamp = 0;
           this.value = 0.0;
        }
    
        public int getTimestamp() {
            return timestamp;
        }
        public double getValue() {
            return value;
        }
        
        public void setTimestamp(int timestamp) {
            this.timestamp = timestamp;
        }
        public void setValue(double value) {
            this.value = value;
        }
    
        @Override
        public String toString() {
            return "[Value: " + value +    "    Timestamp: " + timestamp+ "]";
        }
    }
    On the server I want to create the Hashmap with different temperature signals, but there seems to be a thing with setting the values I didn`t understand yet:
    Java Code:
        @Override
        public Map<String, rmiinterface.ValuePair> getAllSignals(String VIN) throws RemoteException {
    
            rmiinterface.ValuePair valuepair = new rmiinterface.ValuePair();
            HashMap<String, rmiinterface.ValuePair> signals = new HashMap<>();
    
            valuepair.setTimestamp(500);
            valuepair.setValue(80.0);
            signals.put("Temperature_1", valuepair);
    
            valuepair.setTimestamp(250);
            valuepair.setValue(100.0);
            signals.put("Temperature_2", valuepair);
    
            return signals;
    
        }
    Because on the client side it prints:
    Java Code:
    {Temperature_1=[Value: 100.0    Timestamp: 250], Temperature_2=[Value: 100.0    Timestamp: 250]}
    obviously it sets all values and timestamp to the ones which has been set last. How can i prevent this from happening?

  9. #9
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    13,541
    Rep Power
    27

    Default Re: Returning a custom Object via RMI

    The attributes should be private, by the way. The idea is to not expose your state to the outside world except via methods.

    Your current situation is because you only have one ValuePair object. You add it to the Map twice (with different keys), but it's the same object being referenced.
    Please do not ask for code as refusal often offends.

    ** This space for rent **

  10. #10
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    I see,

    the thing is, what I ultimately want to do is this: I have an unknown number of files in a folder. I want to use the file names as my HashMap Key (e.g. Temperature_1), open the files and read the timestamp (int) and value (double) in it.

    I just wanted to use the custom object ValuePair to tell the program how a ValuePair has to look like, if that makes sense.

  11. #11
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    13,541
    Rep Power
    27

    Default Re: Returning a custom Object via RMI

    OK, so loop over the files in a directory and create a ValuePair for each one and put it into the Map.
    Please do not ask for code as refusal often offends.

    ** This space for rent **

  12. #12
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Quote Originally Posted by Tolls View Post
    OK, so loop over the files in a directory and create a ValuePair for each one and put it into the Map.
    Ahh, thank you! Now I got it. So in my simple example from post #8 I just have to create ValuePair "valuepair1" for Temperature 1, and "valuepair2" for Temperature 2.

  13. #13
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    14,422
    Blog Entries
    7
    Rep Power
    28

    Default Re: Returning a custom Object via RMI

    Using RMI, an object implementing the Remote interface stays at the server side; the client receives a stub implementing what was defined in the Remote interface. No methods where defined in the Remote interface, so your client can't do anything with the stub; do this instead:

    a) define an interface, say ValuePairIF that extends the Remote interface and defines your useful methods;
    b) have your ValuePair class implement the ValuePairIF interface;
    c) use the stub transfered by RMI as if it were a ValuePairIF object and use its methods.

    kind regards,

    Jos
    Build a wall around Donald Trump; I'll pay for it.

  14. #14
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Hey JosAH,

    I thought I already have that. I have an Interface Project with an RMI class = ValuePairIF, which extends the Remote Interface and defines one Method (getAllSignals()).
    My ValuePair class is implemented as an additional java class in my Interface package.
    The client calls getAllSignals() and the Server executes this method.
    And the client, as well as the Server create an object ValuePair, with the information they get from the interface`s ValuePair class.

  15. #15
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Quote Originally Posted by Tolls View Post
    OK, so loop over the files in a directory and create a ValuePair for each one and put it into the Map.
    How can I do that within a loop? I have a working method now, that goes through a list of File paths and reads a timestamp and a value out of it.
    I also create a new ValuePair in every iteration, but with the same name. The HashMap I create looks like I want it to. But is there a better way to create a new Object? for example, how can I use i to create a new Object with a different name for every iteration?

    Java Code:
      
    
     public Map<String, rmiinterface.ValuePair> readFiles(ArrayList<Path> fileList, Path dir) throws FileNotFoundException, IOException {
    
            HashMap<String, rmiinterface.ValuePair> signals = new HashMap<>();
    
            //Loop through all files in the ArrayList
            for (int i = 0; i < fileList.size(); i++) {
    
                //handle File notations
                Path currentFilePath = fileList.get(i);
                String fileNameWithExt = currentFilePath.getFileName().toString();
    
                //Get Timestamp and Value from log file
                int timestamp = getCurrentLogTimestamp();
                double value = getCurrentLogValue();
    
                //Write into HashMap
                rmiinterface.ValuePair valuepair = new rmiinterface.ValuePair();
                valuepair.setTimestamp(timestamp);
                valuepair.setValue(value);
                signals.put(fileNameWithExt, valuepair);
    
            }
            System.out.println(signals);
            return signals;

  16. #16
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    Eastern Florida
    Posts
    20,003
    Rep Power
    33

    Default Re: Returning a custom Object via RMI

    how can I use i to create a new Object with a different name for every iteration?
    You can't. variable names are set when you type in the source.
    Why do you think you need different names?
    By saving references to the created objects in a Map or ArrayList, each object can be accessed using the saved reference.

    Or are you asking how to create a different String for the key in the Map? One way would be to concatenate the value of i to the String: String + i
    Last edited by Norm; 09-15-2016 at 04:45 PM.
    If you don't understand my response, don't ignore it, ask a question.

  17. #17
    TomTom1 is offline Member
    Join Date
    Jul 2016
    Posts
    36
    Rep Power
    0

    Default Re: Returning a custom Object via RMI

    Quote Originally Posted by Norm View Post
    You can't. variable names are set when you type in the source.
    Why do you think you need different names?
    By saving references to the created objects in a Map or ArrayList, each object can be accessed using the saved reference.

    Or are you asking how to create a different String for the key in the Map? One way would be to concatenate the value of i to the String: String + i
    Well, my key in the Map is always different, since the file names are different. I meant something like valuepair(i) so valuepair1, valuepair2...
    But like you said, that is redundant since I'm only interested in the information the finished Map gives me.

  18. #18
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    14,422
    Blog Entries
    7
    Rep Power
    28

    Default Re: Returning a custom Object via RMI

    Quote Originally Posted by TomTom1 View Post
    Hey JosAH,

    I thought I already have that. I have an Interface Project with an RMI class = ValuePairIF, which extends the Remote Interface and defines one Method (getAllSignals()).
    My ValuePair class is implemented as an additional java class in my Interface package.
    The client calls getAllSignals() and the Server executes this method.
    And the client, as well as the Server create an object ValuePair, with the information they get from the interface`s ValuePair class.
    I don't see that anywhere in your code; all I see is a package named 'rmiinterface', but that doesn't mean much to the compiler ...

    kind regards,

    Jos
    Build a wall around Donald Trump; I'll pay for it.

  19. #19
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    14,422
    Blog Entries
    7
    Rep Power
    28

    Default Re: Returning a custom Object via RMI

    If your ValuePair object implements a ValuePairIF interface, your client should only refer to a ValuePairIF object. Summarizing: the server knows about ValuePair objects; if it sends them to a client, the client knows about ValuePairIF objects. The ValuePairIF interface should extend the Remote interface. What the client receives is a stub object implementing the ValueIF interface.

    kind regards,

    Jos
    Build a wall around Donald Trump; I'll pay for it.

Similar Threads

  1. problem returning object
    By dendoc01 in forum New To Java
    Replies: 3
    Last Post: 04-10-2013, 07:11 AM
  2. Replies: 1
    Last Post: 06-06-2011, 01:47 PM
  3. Returning an object
    By dom12 in forum New To Java
    Replies: 3
    Last Post: 11-02-2010, 11:30 AM
  4. Returning a ResultSet to custom JTable Model
    By Kenjitsuka in forum New To Java
    Replies: 9
    Last Post: 10-16-2010, 09:17 PM
  5. returning an object from a method
    By bigj in forum New To Java
    Replies: 7
    Last Post: 01-08-2010, 12:39 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •