Десериализация массивов нестандартного типа в OSGi - PullRequest
2 голосов
/ 13 августа 2010

Я пытаюсь отправить объекты из пакетов через выделенный пакет связи в другую среду. Для связи я использую стандартную сериализацию Java (с ObjectStreams) через TCP / IP.

Поток связи следующий: пакет отправителя будет передавать сериализуемые объекты отправителю-отправителю, который будет сериализовывать объекты и отправлять их через TCP / IP передающему-получателю. Затем получатель десериализует полученные объекты и передает их в связку получателя.

Поскольку архитектура загрузки классов OSGi отличается от нативной, я должен сделать небольшой взлом с помощью загрузчика классов: так как я предполагаю, что пакет-получатель должен знать классы, которые он получает (= импортировал их или иным образом доступ его загрузчик классов), я использую загрузчик классов приемника вместо передающего приемника для загрузки класса. (С помощью метода Bundle.loadClass (..)). Это хорошо работает для пользовательских классов, однако, это не работает для массивов пользовательских типов. (Которые не известны загрузчику классов передатчик-приемник, но пакету приемника.)

Редактировать: ObjectInputStream.readObject (...) генерирует исключение ClassNotFoundException, если оно пытается десериализовать массив. (Я предполагаю, что это исключение происходит из метода Bundle.loadClass (...) пакета-получателя.)

Работает с java.util.List или другими сериализуемыми классами. Он также работает для пользовательских типов, которые содержат поля других пользовательских типов, если они не являются массивами.

Так что вопрос: есть ли разница в том, как массивы де / сериализуются? Или они загружены по-разному?

1 Ответ

3 голосов
/ 19 августа 2010

Я подозреваю, что вы реализовали ObjectInputStream.resolveClass, используя Bundle.loadClass напрямую. Если это так, вы столкнулись с этой проблемой: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6516909

По сути, ClassLoader.loadClass никогда не предназначался для использования в классах массивов. Самый простой способ загрузить классы массива - это использовать Class.forName. К сожалению, нет простого способа сделать это с OSGi. Вам потребуется прокси-сервер Bundle ClassLoader или некоторая предварительная обработка имен классов, чтобы убедиться, что вы не передаете массивы напрямую в loadClass:

public static Class<?> bundleClassForName(Bundle bundle, String name) throws ClassNotFoundException {
    int length = name.length();
    if (length > 0 && name.charAt(0) == '[') {
        int pos = 1;
        while (pos < length && name.charAt(pos) == '[') {
            pos++;
        }

        if (pos < name.length()) {
            if (name.charAt(pos) != 'L') {
                return Class.forName(name);
            }

            if (name.charAt(length - 1) == ';') {
                String componentName = name.substring(pos + 1, length - 1);
                Class<?> klass = bundle.loadClass(componentName);
                ClassLoader loader = klass.getClassLoader();
                return Class.forName(name, false, loader);
            }
        }
    }

    return bundle.loadClass(name);
}
...