Java RMI 异常错误



我刚刚开始学习RMI和JFrame,我被困在一个异常上一段时间了。我正在编写一个客户端/服务器交互,它将访问雅虎数据库中的股票信息。

这是我的代码:

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();
    }
}

这是我收到的例外。

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)

堆栈跟踪会准确地告诉您错误是什么。你需要StockQuote影响Serializable,因为RMI使用Java的序列化机制通过网络传输数据(如方法参数和返回值(。

堆栈跟踪中报告的根本原因是

java.io.NotSerializableException: stockquote.股票报价

显然,在尝试序列化的对象的对象图中,有一个名为 stockquote.StockQuote 的类的实例,但该类不可序列化。

从堆栈跟踪的其他部分来看,序列化尝试似乎与调用远程方法的尝试有关 - RMI 依赖于 Java 序列化将参数传递给远程方法并从中接收返回值。

当然,如果您希望能够通过 RMI 传递或返回实例,stockquote.StockQuote必须实现java.io.Serializable。 但是,这可能足以也可能不足以实际序列化实例,具体取决于类的成员。

相关内容

  • 没有找到相关文章

最新更新