Как бороться с LinkageErrors в Java?
разрабатывая сильно основанное на XML Java-приложение, я недавно столкнулся с интересной проблемой на Ubuntu Linux.
мое приложение, используя Java Plugin Framework, не удается преобразовать dom4j-создан XML-документ в батик-это реализация спецификации SVG.
на консоли, я узнаю, что произошла ошибка:
Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) of the current class, org/apache/batik/dom/svg/SVGOMDocument, and the class loader (instance of <bootloader>) for interface org/w3c/dom/Document have different Class objects for the type org/w3c/dom/Attr used in the signature at org.apache.batik.dom.svg.SVGDOMImplementation.createDocument(SVGDOMImplementation.java:149) at org.dom4j.io.DOMWriter.createDomDocument(DOMWriter.java:361) at org.dom4j.io.DOMWriter.write(DOMWriter.java:138)
Я думаю, что проблема вызвана конфликтом между исходный загрузчик классов из JVM и загрузчик классов, развернутый платформой плагинов.
насколько мне известно, невозможно указать загрузчик классов для использования в рамках. Возможно, его можно взломать, но я бы предпочел менее агрессивный подход к решению этой проблемы, поскольку (по какой-то причине) это происходит только в системах Linux.
одна из вас сталкивался с такой проблемой и знает как ее исправить или хотя бы вникнуть в суть вопроса?
5 ответов:
LinkageError-это то, что вы получите в классическом случае, когда у вас есть класс C, загруженный более чем одним загрузчиком классов, и эти классы используются вместе в одном коде (compared, cast и т. д.). Это не имеет значения, если это то же самое имя класса или даже если он загружен из идентичного jar - класс из одного загрузчика классов всегда рассматривается как другой класс, если загружен из другого загрузчика классов.
сообщение (которое значительно улучшилось за эти годы) говорит:
Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) of the current class, org/apache/batik/dom/svg/SVGOMDocument, and the class loader (instance of ) for interface org/w3c/dom/Document have different Class objects for the type org/w3c/dom/Attr used in the signature
Итак, здесь проблема заключается в разрешении SVGOMDocument.createAttribute () метод, который использует org.консорциума W3C.дом.Attr (часть стандартной библиотеки DOM). Но версия Attr, загруженная с помощью Batik, была загружена из другого загрузчика классов, чем экземпляр Attr, который вы передаете методу.
вы увидите, что версия батика, кажется, загружается из плагина Java. И ваш загружается из " ", который, скорее всего, является одним из встроенных JVM загрузчики (boot classpath, ESOM или classpath).
три известных модели загрузчика классов:
- делегирование (по умолчанию в JDK-спросите родителя, а затем меня)
- пост-делегирование (обычно в плагинах, сервлетах и местах, где вы хотите изоляцию-спросите меня, а затем родителя)
- брат (распространенный в моделях зависимостей, таких как OSGi, Eclipse и т. д.)
Я не знаю, какую стратегию делегирования использует загрузчик классов JPF, но ключ заключается в том, что вы хотите, чтобы одна версия библиотеки dom была загружена, и каждый источник этого класса из того же места. Это может означать удаление его из пути к классам и загрузку в качестве плагина, или предотвращение загрузки батика, или что-то еще.
звучит как проблема иерархии загрузчиком. Я не могу сказать, в какой среде развернуто ваше приложение, но иногда эта проблема может возникнуть в веб-среде - где сервер приложений создает иерархию загрузчиков классов, напоминающую что-то вроде:
javahome/lib-как root
appserver / lib - как потомок root
веб-приложения/веб-инф/Либ - как дитя дитя корневой
и т. д.обычно загрузчики классов делегируют загрузку своим родителям загрузчик классов (это называется"
parent-first
"), и если этот загрузчик классов не может найти класс, то дочерний загрузчик классов пытается. Например, если класс развернут как Jar в веб-приложения/веб-инф/Либ пытается загрузить класс, первый просит загрузчика классов, соответствующий серверу приложений/lib для нагрузки класса (который, в свою очередь, просит загрузчик классов, соответствующие каталог-Java/lib, чтобы загрузить класс), и если этот поиск завершается неудачей, то веб-инф/Либ ищется матч в этом классе.в интернете окружение, вы можете столкнуться с проблемами с этой иерархией. Например, одна ошибка/проблема, с которой я столкнулся раньше, заключалась в том, что класс в WEB-INF/lib зависел от класса, развернутого в appserver/lib, который, в свою очередь, зависел от класса, развернутого в WEB-INF / lib. Это вызвало сбои, потому что, хотя загрузчики классов могут делегировать Родительский загрузчик классов, они не могут делегировать обратно вниз по дереву. Так, в веб-инф/Либ класслоадер бы задать серверу приложений/Либ classloader для класса, серверу приложений/Либ загрузчика классов загрузит этот класс и попытается загрузить зависимый класс, и не удастся, так как он не может найти этот класс в appserver/lib или javahome/lib.
таким образом, хотя вы не можете развертывать свое приложение в среде сервера веб-приложений, мое слишком длинное объяснение может применяться к вам, если в вашей среде настроена иерархия загрузчиков классов. Так ли это? JPF делает какую-то магию загрузчика классов, чтобы иметь возможность реализовать функции плагина?
может быть это поможет кому-то, потому что это работает очень хорошо для меня. Проблему можно решить путем интеграции собственных зависимостей. Следуйте этим простым шагам
сначала проверьте ошибку, которая должна быть такой:
- ошибка выполнения метода:
- java.ленг.LinkageError: нарушение ограничений загрузчика:
- при разрешении метода " org.slf4j.осущ.StaticLoggerBinder.getLoggerFactory()Lorg / slf4j / ILoggerFactory;"
- загрузчик класса (экземпляр org/openmrs/module/ModuleClassLoader) текущего класса, org / slf4j/LoggerFactory,
- и загрузчик классов (экземпляр org / apache / catalina/loader / WebappClassLoader) для разрешенного класса, org / slf4j / impl/StaticLoggerBinder,
- имеют различные объекты класса для типа taticLoggerBinder.getLoggerFactory () Lorg / slf4j / ILoggerFactory; используется в подпись
см. два выделенных класса. Поиск Google для них, как " StaticLoggerBinder.класс jar скачать " & " LoggeraFactory.скачать класс баночка". Это покажет вам первую или в некоторых случаях вторую ссылку (сайт http://www.java2s.com), которая является одной из версий jar, которые вы включили в свой проект. Вы можете легко идентифицировать его самостоятельно, но мы зависимы от google;)
после этого вы будете знайте имя файла jar, в моем случае это похоже на slf4j-log4j12-1.5.6.jar & slf4j-api-1.5.8
- теперь последняя версия этого файла доступна здесь http://mvnrepository.com/ (на самом деле все версии до настоящего времени, это сайт, откуда maven получает ваши зависимости).
- теперь добавьте оба файла в качестве зависимостей с последней версией (или сохраните обе версии файлов одинаковыми, либо выбранная версия старая). Ниже приводится зависимость, которую вы должны включить в ПФЛ.xml
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency>
можно ли указать загрузчик классов? Если нет, попробуйте указать загрузчик классов контекста следующим образом:
Thread thread = Thread.currentThread(); ClassLoader contextClassLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(yourClassLoader); callDom4j(); } finally { thread.setContextClassLoader(contextClassLoader); }
Я не знаком с Java Plugin Framework, но я пишу код для Eclipse, и я сталкиваюсь с подобными проблемами время от времени. Я не гарантирую, что это исправит это, но это, вероятно, стоит попробовать.
ответы от Алекса и Мэтта очень полезны. Я тоже мог бы извлечь пользу из их анализа.
У меня была такая же проблема при использовании библиотеки Batik в рамках Netbeans RCP, библиотека Batik была включена в качестве "модуля-оболочки библиотеки". Если какой-либо другой модуль использует XML-API, и для этого модуля не требуется и не устанавливается зависимость от Batik, проблема нарушения ограничений загрузчика классов возникает с аналогичными сообщениями об ошибках.
В Netbeans, отдельные модули используют выделенные загрузчики классов, и отношение зависимости между модулями подразумевает подходящую маршрутизацию делегирования загрузчика классов.
Я мог бы решить эту проблему, просто опустив файл jar xml-API из пакета библиотеки Batik.