Search code examples
javaserializationrminotserializableexception

Java RMI Exception Error


I am just starting to learn RMI and JFrame and I have been stuck on an exception for a bit. I'm writing a client/server interaction that will access stock information from yahoo's database.

Here's my code:

package stockquote;

public class StockQuote{

    public double currentPrice, priceChange, dailyLow, dailyHigh;

    public StockQuote(double price, double change, double low, double high){
        currentPrice = price;
        priceChange = change;
        dailyLow = low;
        dailyHigh = high;
    }

    public StockQuote(){
        currentPrice = 0;
        priceChange = 0;
        dailyLow = 0;
        dailyHigh = 0;
    }
}



package stockquote;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface StockQuoteInterface extends Remote{
    public StockQuote getQuote(String symbol) throws RemoteException;
}



package stockquote;

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.UnicastRemoteObject;

import java.io.*;
import java.util.Properties;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.rmi.RemoteException;
import java.util.*;

public class StockQuoteServer implements StockQuoteInterface{

    public StockQuote getQuote(String symbol) throws RemoteException{

        StockQuote information = new StockQuote();

        try{
            URL url = new URL("http://download.finance.yahoo.com/d/quotes.csv?s=" + symbol + "&f=l1c1hg");
            URLConnection conn = url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String quoteString = in.readLine();
            in.close();

            String[] data = quoteString.split(",");

            information.currentPrice = Double.parseDouble(data[0]);
            information.priceChange = Double.parseDouble(data[1]);
            information.dailyHigh = Double.parseDouble(data[2]);
            information.dailyLow = Double.parseDouble(data[3]);

        }catch(Exception e){
            e.printStackTrace();
        }

        return information;
    }

    public static void main(String[] args) throws Exception {
        try {
            StockQuoteServer obj = new StockQuoteServer();
            StockQuoteInterface stub = (StockQuoteInterface) UnicastRemoteObject.exportObject(obj, 0);

            Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);

            registry.rebind("StockQuoteServer", stub);   
            System.err.println("StockQuote Server is running.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}



package stockquote;

import javax.swing.*;

import java.awt.*;
import java.awt.event.*;
import java.rmi.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.*;

public class StockQuoteClient extends JFrame implements ActionListener{
    private static final long serialVersionUID = 1L;

    private static StockQuoteInterface stockQuote;

    private JTextField symbolField = new JTextField(10);
    private JTextField currentPriceField = new JTextField(10);
    private JTextField priceChangeField = new JTextField(10);
    private JTextField dailyHighField = new JTextField(10);
    private JTextField dailyLowField = new JTextField(10);
    private JButton lookup = new JButton("Lookup");

    public StockQuoteClient() throws RemoteException{

        try {
            Registry registry = LocateRegistry.getRegistry("localhost");
            stockQuote = (StockQuoteInterface) registry.lookup("StockQuoteServer");

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }

        this.setLayout(new GridLayout(0,1));
        JPanel symbolPanel = new JPanel();
        symbolPanel.add(new JLabel("Stock Symbol: "));
        symbolPanel.add(symbolField);
        this.add(symbolPanel);

        this.setLayout(new GridLayout(0,1));
        JPanel fieldsPanel = new JPanel();
        fieldsPanel.add(new JLabel("Current Price: "));
        fieldsPanel.add(currentPriceField);
        fieldsPanel.add(new JLabel("Price Change: "));
        fieldsPanel.add(priceChangeField);
        fieldsPanel.add(new JLabel("Daily High: "));
        fieldsPanel.add(dailyHighField);
        fieldsPanel.add(new JLabel("Daily Low: "));
        fieldsPanel.add(dailyLowField);
        this.add(fieldsPanel);

        JPanel lookupButtonPanel = new JPanel();
        lookupButtonPanel.add(lookup);
        this.add(lookupButtonPanel);

        lookup.addActionListener(this);

        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setSize(240, 350);
        this.setVisible(true);

    }

    public void actionPerformed(ActionEvent e){ 
        StockQuote quoteInfo = new StockQuote();

        Object source = e.getSource();

        try{
            if(source == lookup){
                String symbol = symbolField.getText().trim();
                quoteInfo = stockQuote.getQuote(symbol);
                if(quoteInfo.currentPrice == 0.0){
                    currentPriceField.setText("Error");
                    priceChangeField.setText("Error");
                    dailyHighField.setText("Error");
                    dailyLowField.setText("Error");
                }else{
                    currentPriceField.setText(Double.toString(quoteInfo.currentPrice));
                    priceChangeField.setText(Double.toString(quoteInfo.priceChange));
                    dailyHighField.setText(Double.toString(quoteInfo.dailyHigh));
                    dailyLowField.setText(Double.toString(quoteInfo.dailyLow));
                }
            }
        }catch(RemoteException ex){
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) throws RemoteException{
        /*StockQuote ggg = new StockQuote();

        Scanner keyboard = new Scanner(System.in);
        System.out.println("Enter a symbol: ");
        String symbol = keyboard.nextLine();

        ggg = stockQuote.getQuote(symbol);

        System.out.println(ggg.currentPrice);*/
        new StockQuoteClient();
    }

}

And here is the exception I am receiving.

Exception in thread "main" java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: stockquote.StockQuote
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
at com.sun.proxy.$Proxy0.getQuote(Unknown Source)
at stockquote.StockQuoteClient.main(StockQuoteClient.java:101)
Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: stockquote.StockQuote
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)
... 5 more
Caused by: java.io.NotSerializableException: stockquote.StockQuote
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at sun.rmi.server.UnicastRef.marshalValue(Unknown Source)
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$256(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Solution

  • The stacktrace tells you exactly what the error is. You need make StockQuote impement Serializable, because RMI uses Java's serialization mechanism to transmit data (such as method arguments and return value) over the wire.