java.lang.ClassCastException: java.io.ObjectStreamClass не может быть приведен к [MyClass]

В настоящее время я реализую функцию поиска, когда введенная пользователем строка отправляется на сервер, который просматривает базу данных и отправляет всех пользователей, чье имя пользователя соответствует данной строке, обратно клиенту. Для передачи я использую пользовательский класс Message, который содержит строку, содержащую действие, которое необходимо выполнить (здесь не имеет значения), и объект, который является фактическим сообщением. В данном случае это будет ArrayList<User>. Я использую метод writeObject() из ObjectOutputStream и readObject() из ObjectInputStream для передачи данных. После получения данных я привожу объект к объекту сообщения, и именно здесь я получаю исключение. Примечание: приведение к Message отлично работает в любой другой точке кода, но здесь выдается исключение.

Исключение:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: java.io.ObjectStreamClass cannot be cast to gruber.common.Message
    at gruber.client.controller.ChatRoomController.lambda$searchForUser$2(ChatRoomController.java:105)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(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$147(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)

Сторона клиента:

 private void searchForUser(){
        try {
                oos.writeObject(new Message("SEARCH", searchfield.getText()));
                oos.flush();

                Message results = (Message)ois.readObject();

                ArrayList<User> users = (ArrayList<User>)results.getMsg();
                for(User u: users) {
                    System.out.println(u.getUsername());
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

Сторона сервера:


 private void search() throws SQLException, IOException {
    Message client_msg = (Message) client.getOis().readObject();
    String searchParam = client_msg.getMsg();
        PreparedStatement searchUsers = con.prepareStatement("SELECT username, image from chatuser where username like ?");
        searchUsers.setString(1, searchParam);
        ResultSet results = searchUsers.executeQuery();
        ArrayList<User> users = new ArrayList<>();

        while (results.next()) {
            users.add(new User(results.getString(1), results.getBytes(2)));
        }

        client.getOos().writeObject(new Message("SEARCH", users));
        client.getOos().flush();
    }

Класс сообщения (если применимо):

package gruber.common;

import java.io.Serializable;

public class Message implements Serializable {
    private String action;
    private Object msg;

    public Message(String action, Object msg) {
        this.action = action;
        this.msg = msg;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public Object getMsg() {
        return msg;
    }

    public void setMsg(Object msg) {
        this.msg = msg;
    }
}

comment
Этот стек исключений на сервере или на клиенте? Является ли User сериализуемым?   -  person M. Prokhorov    schedule 02.03.2020
comment
Стек исключений находится на стороне клиента, и да, пользователь сериализуем.   -  person Grual    schedule 02.03.2020


Ответы (1)


Если класс реализует сериализуемость, он должен определить атрибут serialVersionUID со значением, которое вы можете свободно определить.

private static final long serialVersionUID = 1L;

Если вы не определите serialVersionUID, он будет сгенерирован java и может отличаться на разных JVM, в результате чего объект не может быть заменен между этими JVM.

Поскольку вы говорите о клиенте и сервере, я предполагаю, что JVM могут быть разными на клиенте и сервере. Ваш класс Message реализует Serializable, но не имеет определения serialVersionUID. Попробуйте добавить этот атрибут. То же самое справедливо и для вашего пользовательского объекта.

person Sergej Masljukow    schedule 02.03.2020
comment
Это ничего не изменило. - person Grual; 02.03.2020
comment
В целях устранения неполадок оставьте слепок подальше. Измените строку Message results = (Message)ois.readObject(); на Object results = ois.readObject();, закомментируйте строки кода, которые не будут компилироваться, затем установите точку останова сразу за этой строкой и проверьте результаты объекта в отладчике. Возможно, по содержимому объекта результатов вы поймете, что происходит не так. - person Sergej Masljukow; 02.03.2020
comment
Я попробовал это, и отладчик сказал мне, что он распознал, что это объект Message, однако по какой-то причине он все еще является объектом ObjectStreamClass. Странно то, что я также проверил с помощью отладчика, что происходит в других точках кода, когда я сохраняю вывод readObject в переменную объекта и привожу его к Message, и в любой другой точке кода это работает совершенно нормально, потому что поток распознает его как объект Message и обрабатывает его как таковой. - person Grual; 03.03.2020
comment
На самом деле, если мне позволено предложить вам что-то, то сериализованные объекты Java - не лучший выбор для формата обмена. С этим интерфейсом вы никогда не сможете заменить свою имплементацию (клиентскую или серверную часть) чем-то другим, кроме java. Если вы будете использовать json внутри, то ваш сервер или клиент может быть любым. А маршалинг java-объекта в json и демаршалинг обратно в java-объект на самом деле не сложны. - person Sergej Masljukow; 03.03.2020
comment
Спасибо за ваше предложение! На самом деле я только что нашел ошибку в своей программе. Это действительно специфично для моей программы. У меня было два последовательных потока, которые оба вызывали ois.readObject(); Теперь я поместил его в поток, который фактически отвечает за обработку ответов сервера, а не в поток рисования, который я делал раньше, глупо, я знаю. Теперь все работает отлично, но спасибо за помощь! - person Grual; 03.03.2020