Ошибка Java Kryonet при отправке объекта

Я использую Kryonet для TCP-отправки объектов, в частности, с именем TransferMessage:

public static class TransferMessage{String text; String username; Color color = Color.black;}

Теперь я знаю, что мне нужно вызвать kryo.register(TransferMessage.class), но когда я пытаюсь подключиться к серверу со всеми зарегистрированными классами, я получаю сообщение об ошибке:

    Exception in thread "Server" com.esotericsoftware.kryo.KryoException: java.lang.IllegalArgumentException: Class is not registered: java.awt.Color
Note: To register this class use: kryo.register(java.awt.Color.class);
Serialization trace:
color (com.andrewlalisofficial.MessageTypes$TransferMessage)
    at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.write(FieldSerializer.java:585)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.write(FieldSerializer.java:213)
    at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:571)
    at com.esotericsoftware.kryonet.KryoSerialization.write(KryoSerialization.java:50)
    at com.esotericsoftware.kryonet.TcpConnection.send(TcpConnection.java:192)
    at com.esotericsoftware.kryonet.Connection.sendTCP(Connection.java:59)
    at com.esotericsoftware.kryonet.Server.sendToAllTCP(Server.java:435)
    at com.andrewlalisofficial.ChatServer.sendMessage(ChatServer.java:204)
    at com.andrewlalisofficial.ChatServer.checkCommand(ChatServer.java:124)
    at com.andrewlalisofficial.ChatServer$1.received(ChatServer.java:72)
    at com.esotericsoftware.kryonet.Server$1.received(Server.java:61)
    at com.esotericsoftware.kryonet.Connection.notifyReceived(Connection.java:246)
    at com.esotericsoftware.kryonet.Server.update(Server.java:208)
    at com.esotericsoftware.kryonet.Server.run(Server.java:356)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: Class is not registered: java.awt.Color

Я не понимаю, потому что, хотя мой зарегистрированный класс использует класс Color, мне никогда раньше не приходилось регистрировать объекты String, поэтому я не вижу, в чем здесь разница, и как мне исправить эту ошибку? Спасибо заранее за вашу помощь.

ИЗМЕНИТЬ :

Вот минимальный воспроизводимый код, показывающий ошибку при сериализации Color :

// this works actually fine
public static void main(String[] args) {
    Kryo kryo = new Kryo();
    kryo.register(Color.class, new JavaSerializer());

    Color color = new Color(15006);

    Output output = new Output(new byte[1024]);
    kryo.writeObject(output, color);

    Input input = new Input(output.getBuffer());
    Color color2 = kryo.readObject(input, Color.class);

    if (!color.equals(color2)) throw new AssertionError();
}

person Andrew Lalis    schedule 01.10.2015    source источник
comment
Это не идеально сделано. Я бы расширил KryoRegistrator и использовал его для инициализации одного экземпляра Kryo на каждой стороне TCP-соединения. Это означает, что обе стороны зарегистрировали одни и те же классы с одними и теми же сериализаторами.   -  person Dici    schedule 01.10.2015
comment
На самом деле это работает с JavaSerializer, если все сделано правильно. Не знаю, в чем ваша точная проблема. Я посмотрел на код Color, и кажется, что много данных будет сериализовано, тогда как их можно просто реконструировать после десериализации. Я думаю, что вы можете смело придерживаться обычного сериализатора, он немного эффективнее, если только реконструкция частных атрибутов, которые мы не сериализуем, не дороже, чем сетевые затраты на их сериализацию.   -  person Dici    schedule 01.10.2015


Ответы (1)


String должен быть зарегистрирован по умолчанию. Я сам немного удивлен этой ошибкой, потому что мне всегда удавалось сериализовать классы, которые я не регистрировал, просто потому, что Kryo обладает сериализаторами по умолчанию для тривиально сериализуемых классов. В любом случае, поскольку java.awt.Color реализует java.io.Serializable, я бы просто сделал

kryoRegistrator.register(Color.class, new JavaSerializer());

Вы также можете написать свой собственный сериализатор (используя Kryo), если хотите, но я не уверен, что оно того стоит (это просто простое целое число для сериализации, стандартная библиотека никак не может сделать это неэффективно). Если все же хотите, то вот:

public class ColorSerializer extends Serializer<Color> {
    @Override
    public Color read(Kryo kryo, Input input, Class<Color> clazz) {
        return new Color(input.readInt());
    }

    @Override
    public void write(Kryo kryo, Output output, Color color) {
        output.write(color.getRGB());
    }
}
person Dici    schedule 01.10.2015
comment
Я сделал это, но теперь я получаю эту ошибку: Исключение в потоке Клиент com.esotericsoftware.kryonet.KryoNetException: Ошибка во время десериализации. на com.esotericsoftware.kryonet.TcpConnection.readObject(TcpConnection.java:141) на com.esotericsoftware.kryonet.Client.update(Client.java:247) на com.esotericsoftware.kryonet.Client.run(Client.java:333) ) на java.lang.Thread.run(Thread.java:745) Причина: com.esotericsoftware.kryo.KryoException: ошибка во время десериализации Java. - person Andrew Lalis; 01.10.2015
comment
Хорошо, это озадачивает. У вас есть воспроизводимый код для этого? Можете ли вы написать минимальный код, просто используя ваши классы данных и Kryo? Можете ли вы также попробовать написать свой собственный сериализатор Kryo для Color? - person Dici; 01.10.2015
comment
Я не знаю, как создать свой собственный сериализатор, и, глядя на документы, я не вижу, что бы я переопределил. Ошибка возникает, когда клиент получает объект TransferMessage, содержащий сериализованный объект Color. - person Andrew Lalis; 01.10.2015
comment
Это очень легко. Я покажу это вам, но, пожалуйста, попробуйте построить мне небольшой пример, воспроизводящий ошибку. Я хочу это понять. - person Dici; 01.10.2015
comment
Просто введите код, который у меня есть. Чтобы сделать его небольшим, но воспроизводимым, в основном потребуется написать три совершенно новые программы, поэтому, надеюсь, того, что у меня есть, достаточно. - person Andrew Lalis; 01.10.2015