С gcj, скомпилированным java и XStream. (Исключение: невозможно создать XmlPullParser)

Я улучшаю клиента, который является частью более крупного проекта. Из-за нехватки скорости я был вынужден переключиться на CNI, и поэтому мне пришлось генерировать собственный код с помощью компилятора GNU-gcj (gnu 4.6.3).

Компиляция и компоновка работают нормально (благодаря флагу -findirect-dispatch), и у меня нет проблем с выполнением вывода. Но когда дело доходит до связи между клиентом и сервером, клиент сразу отключается. Причина:

[XStreamClient Reader] ПРЕДУПРЕЖДЕНИЕ. Клиент отключен (Исключение: com.thoughtworks.xstream.io.StreamException: невозможно создать XmlPullParser)

(Это исключение появляется только в версии клиента, скомпилированной gcj. Когда я запускаю код с помощью интерпретатора java, все работает хорошо (но слишком медленно ^^)) --> Сложность заключается в том, что я не могу получить исходный код. код, в котором возникает это исключение, потому что он находится в предварительно скомпилированной (файлы классов Java) библиотеке, которую использует клиент. (И я не могу связаться с автором той библиотеки)

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

Я привязываю библиотеку XStream (версия 1.4.3) (и другие необходимые файлы *.jars), распаковывая их и компилируя созданные файлы *.class, а затем связывая объектные файлы. Похоже, это работает и для всех других библиотек. (Моя ОС=Убунту)

Что я уже сделал, чтобы решить эту проблему: я интенсивно гуглил XStream/XmlPullParser и gcj и заменил файлы xmlpull и kxml2 другими версиями. Но ничего не сработало. Кто-нибудь из вас знает, что может быть решением?

РЕДАКТИРОВАТЬ:

Я выяснил, что причина сбоя создания XmlPullParser заключается в том, что каталог META-INF с файлом /services/org.xmlpull.v1.XmlPullParserFactory не может быть найден функцией XmlPullParserFactory.newInstance. Это связано с тем, что я скомпилировал и связал только файлы *.jar *.class. Итак, как только я нашел способ связать каталог META-INF с исполняемым файлом, чтобы функция могла найти и получить к нему доступ, проблема должна быть решена. Кто-нибудь из вас уже знает, как это сделать?


person Chris    schedule 21.10.2012    source источник
comment
для меня эта ошибка была вызвана отсутствием библиотеки xpp3_min-1.1.4c.jar.. (не проблема компиляции)   -  person teejay    schedule 07.05.2013


Ответы (3)


Я думаю, что xmlpull нужна реализация, которая может использовать xpp3 в качестве своей реализации. Пожалуйста, добавьте следующий код в ваш pom.xml и, при необходимости, добавьте эти jar-файлы в программное обеспечение, для которого они требуются.

<dependency>
    <groupId>xmlpull</groupId>
    <artifactId>xmlpull</artifactId>
    <version>1.1.3.1</version>
</dependency>
<dependency>
    <groupId>xpp3</groupId>
    <artifactId>xpp3</artifactId>
    <version>1.1.3.3</version>
</dependency>
person sendon1982    schedule 22.12.2013

Я думаю, что вы сделали пару ошибок в выборе платформы для реализации:

  • Вам, вероятно, не нужно было прилагать все усилия для реализации вещей в нативном коде «для скорости». Для большинства вещей вы можете получить примерно сравнимую скорость в Jana и в нативном коде, особенно если вы потратите время на профилирование и оптимизацию кода Java.

  • Если предположить, что вы это сделали, CNI был плохим выбором. Вам было бы лучше использовать JNI или JNA, оба из которых позволяют вам использовать выпуски Oracle HotSpot / OpenJDK.

  • GCJ — плохой выбор, потому что (как вы заметили) некоторые вещи не работают, а отладка затруднена. (См. также Умер ли компилятор GNU Java (GCJ)?)

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

Мой совет — пересмотреть как можно больше таких «ошибок».

person Stephen C    schedule 21.10.2012
comment
Спасибо за ваш ответ, @Stephen C! Клиент должен работать над очень критичными по времени задачами (даже очень небольшое увеличение его скорости дает большой эффект). Но переписать весь проект на C/C++ или даже местами на ассемблере было бы слишком много работы для минимального увеличения скорости. Поэтому использование JNI было моей первой идеей. Затем я узнал о CNI и прочитал, что он более эффективен. Я провел несколько тестов скорости, и CNI оказался лучшим выбором для алгоритмов, которые я хочу использовать. Поскольку CNI находится в режиме обслуживания, я подумал, что должен быть способ заставить его работать. Но если окажется, что нет, я буду использовать JNI. - person Chris; 21.10.2012
comment
Да... ну, я все еще думаю, что вы сделали неправильный выбор, и что вы расплачиваетесь за это. Если бы я был вашим продакт-менеджером, я бы попросил конкретные цифры, подтверждающие ваши предположения о том, что задачи действительно критичны по времени и что решение на чистом Java действительно не работает. (Это попахивает преждевременной оптимизацией.) Я не могу предложить вам никакой помощи, чтобы заставить ваш текущий подход работать. - person Stephen C; 22.10.2012

Как я уже отредактировал в своем вопросе, причина сбоя создания заключается в том, что метод XmlPullParserFactory.newInstance не может получить доступ к файлу /META-INF/services/org.xmlpull.v1.XmlPullParserFactory, используя следующую строку кода:

InputStream is = context.getResourceAsStream (RESOURCE_NAME);

(RESOURCE_NAME равно «/META-INF/services/org.xmlpull.v1.XmlPullParserFactory»)

Должен признаться, что я не нашел способа привязать нужный каталог META-INF к исполняемому файлу, что было бы одним из самых элегантных решений. Но поскольку Файл XmlPullParserFactory.java (и библиотека XStream) является открытым исходным кодом, вам просто нужно добавить одну строку кода в исходный файл выше и заменить старый класс новым - и все.

В функции public static XmlPullParserFactory newInstance (String classNames, Class context) программа хочет читать из файла RESOURCE_NAME только тогда, когда classNames == null. Чтобы избежать этого, мы сами присваиваем содержимое файла RESOURCE_NAME переменной classNames и для этого размещаем эту строку кода над оператором if (classNames == null || classNames.length() == 0 || "DEFAULT".equals(classNames)):

classNames = "org.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer";

«org.xmlpull.mxp1.MXParser, org.xmlpull.mxp1_serializer.MXSerializer» — это содержимое моего файла RESOURCE_NAME. Если содержимое вашего файла отличается от моего -> вставьте вместо него свой.

С уважением, Крис

person Chris    schedule 24.10.2012