Отправить анонимный класс через сокеты? (Object..Stream в Java) - PullRequest
5 голосов
/ 26 февраля 2012

Итак, сейчас у меня есть сервер, который работает с ObjectInputStream и ObjectOutputStream.

Проблема, с которой я столкнулся, заключается в том, что у меня есть собственный (анонимный) класс, который расширяет java.lang.DateЯ пытаюсь отправить клиенту и затем скомпилировать.

Так что нигде я не определяю класс на стороне клиента, но я хочу скомпилировать класс программно.Я пробовал много разных методов, но каждый раз получаю ClassNotFoundException, потому что изначально класс не на стороне клиента.

Class<?> dateClass = (Class<?>) in.readObject(); //This is where the CNF Exception occurs
Compiler.compileClass(dateClass);

1 Ответ

7 голосов
/ 26 февраля 2012

Механизм Java Serialization предполагает, что классы известны для десериализации JVM, он не отправляет определения классов.В частности, когда вы сериализуете объект Class, вы не отправляете байт-код для этого класса, а только указываете принимающей ВМ искать объект Class для класса с определенным именем.

Также обратите внимание, что объект Class представляет класс, определенный в JVM, т.е. байт-код класса уже загружен.Нет смысла пытаться скомпилировать в класс, чтобы сгенерировать этот байт-код после загрузки класса.

Итак, нам нужно как-то передать определение класса клиенту.Самый простой подход состоит в том, чтобы сделать это, как любой другой класс, который нужен клиенту (упаковав его в jar-файл клиента или любым другим способом, который вы используете для установки клиентской программы).Если это невозможно, вы можете загрузить определение класса по сети, например, с помощью URLClassLoader, или вы можете отправить файл класса через поток сериализации, а после получения его на клиенте использовать ClassLoader.defineClass для загрузкиclass.

PS: Эта проблема полностью не зависит от того, назван класс или нет.Следующий тестовый код показывает, что объекты анонимных классов можно сериализовать и десериализовать очень хорошо (если у принимающей ВМ есть определение класса):

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
        Serializable payload = new Serializable() {
            @Override
            public String toString() {
                return "hello from the anonymous class";
            }
        };
        oos.writeObject(payload);
        oos.writeObject(payload.getClass());
    }

    try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
        System.out.println(in.readObject());
        System.out.println(in.readObject());
    }
...