Xpoint
   [напомнить пароль]

Как узнать откуда был загружен класс

Метки: [без меток]
[арх]
2006-05-17 19:54:46 [обр] GRAy(14/259)[досье]
Как узнать из какого jar-файла был загружен тот или иной класс.
спустя 1 час 14 минут [обр] Даниэль Алиевский(35/125)[досье]

Единственное, что приходит в голову - перебрать все jar-ы из classpath, самостоятельно их открыть и поискать в них данный класс. Первый jar (или подкаталог), где класс будет обнаружен - это и есть требуемый jar. Если не учитывать возможный параметр -Xbootclasspath при запуске java. И если не учитывать нестандартные реализации ClassLoader, которые могут загружать классы по своим правилам.

А зачем это понадобилось?

спустя 44 минуты [обр] 30-ый(59/584)[досье]
При поиске загадочных ClassNotFound может очень пригодится. При сборке больших проектов на этих загадках с разными версиями библиотек время неделями теряется.
спустя 1 минуту [обр] GRAy(14/259)[досье]
А зачем это понадобилось?

На сервер установлено приложение, которое при инициализации орёт, что нет такого-то поля у такого-то класса. В jar`е, который включен в приложение в нужном классе нужное поле присутсвует, но при проверке runtime версии этого же класса (в error.jsp) - поля нет. Это может означать только одно - класс уже загружен лоадером ранее и приложение пытается использовать его, а не свой. Перенастройка приложения таким образом, чтобы оно приоритетно использовало свои библиотеки приводит к другому конфликту - несовместимые определения, но уже с другим классом. Самое печальное то, что ни первый вызвающий ошибку класс, ни второй, не получается найти по всему серверу стандартными способами (поиск по всем jar`ам файла "ИмяКласса.class"), но ведь он где-то есть ;) раз конфликт возникает.
Список загруженных jar`ов из класслоадера получить несложно, но возникает три проблемы:

  1. их там много.
  2. некоторые из них фактически в системе отсутствуют (?! как это мне не понятно), дублируются или лежат совсем не по тому пути который показывает класслоадер.
  3. из п.2. следует, что, скорее всего, используется некий специфичный класслоадер и доверия к этому списку что-то нет + получаю я этот список в виде простой строки при toString() и что он туда вписывает на самом деле ХЗ.

30-ый[досье] Ну почти мой случай ;) только прикладу писал не я, что проблему только усугубляет млин.

спустя 13 часов [обр] Даниэль Алиевский(35/125)[досье]

Конечно, ClassLoader не обязан сообщать, откуда и как он загружает свои классы. Может быть, он вообще их берет из Web :) Если хочется расследовать ситуацию, может быть, будет полезно пробежаться по цепочке родительских ClassLoader (getParent()), а также распечатать (через рефлексию) все скрытые поля этих ClassLoader-ов, если хватит прав вызвать для этих полей setAccessible. Но только все это очень странные игры, IMHO :)

Почему бы тривиально не выделить проблемный класс (или пакет) в отдельный jar и не попытаться загружать его приоритетно?

спустя 10 минут [обр] GRAy(14/259)[досье]
Но только все это очень странные игры, IMHO

Если бы всё работало - я бы не стал даже заморачиваться ;)

Почему бы тривиально не выделить проблемный класс (или пакет) в отдельный jar и не попытаться загружать его приоритетно?

Даниэль Алиевский[досье] Для этого надо его найти ;) чтобы понять в каком месте он может грузиться и поставить правильный в нужное место. Хотя попробывать наугад повставлять его в разные места можно.

спустя 1 день 1 час [обр] Robinzon(12/14)[досье]

GRAy[досье]

Самое печальное то, что ни первый вызвающий ошибку класс, ни второй, не получается найти по всему серверу стандартными способами (поиск по всем jar`ам файла "ИмяКласса.class"), но ведь он где-то есть ;) раз конфликт возникает.

вот это пугает больше всего
- вы уверены что поиск проходил по всем злачным местам? кэши?
  (возможно их стоит почистить или поискать в них)
- ввиду того что есть такая штука как наследование и интерфейсы
  "поиск по всем jar`ам файла "ИмяКласса.class"" может не гарантировать успеха
  возможно вам стоит сделать поправку на это

спустя 12 минут [обр] GRAy(14/259)[досье]
вы уверены что поиск проходил по всем злачным местам? кэши?

Весь диск сервера достаточный охват? ;) думаю да.

ввиду того что есть такая штука как наследование и интерфейсы

При чём тут это?
ЗЫ. Проблема рассосалась сама собой. Видимо конфликтующий класс использовался только в момент первичной инициализации приложения (создание струтуры БД и т.п.), и переключение контекстов загрузки таки позволило ему сделать всё что требуется и перейти на штатный режим работы. Как? - я видимо уже никогда не узнаю ;)

спустя 2 месяца [обр] Саша[досье]

Немного поздновато...
Тем не менее не смог пройти мимо такого простого вопроса вызвавшего ТАКОЕ эмоциональное обсуждение.
Допустим ты определяешь откуда загружен класс mypackage.Foo. Останавливаешься дебугером в нужном месте и вычисляешь следующее выражение:

mypackage.Foo.class.getClassLoader().getResource("mypackage/Foo.class")

Его результатом является объект класса java.net.URL и указывает на место откуда был загружен класс-файл.
Например: jar:file:///C:/Projects/HelloWorldProj/lib/foo.jar!/mypackage/Foo.class

PS: Вместо дебугера можно использовать отладочную распечатку в коде, кому как проще ;-)

спустя 4 часа 42 минуты [обр] GRAy(14/259)[досье]
Саша[досье] Хм, а подсунуть getResource`у класс в качестве аргумента я и не додумался ;))) Спасибо, возьму на заметку.
спустя 15 дней [обр] Даниэль Алиевский(35/125)[досье]

Саша[досье] Это опять же справедливо лишь для стандартного, умолчательного ClassLoader. Я сам однажды писал ClassLoader, который загружает классы по своим правилам (из специального каталога, "привязанного" к некоему пользовательскому документу, живущему где угодно на диске), но при этом при загрузке ресурсов передает управление системному ClassLoader. (Классы, загружаемые моим ClassLoader, обычно не нуждались в ресурсах.)

Но, конечно, шансы найти велики - идея хорошая. Достаточно качественный ClassLoader вряд ли будет загружать ресурсы из другого места.

Powered by POEM™ Engine Copyright © 2002-2005