Некоторые недокументированные функции Java::Журнал СА 3.2003
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

Разбор полетов  

Ошибок опыт трудный

Как часто мы легко повторяем, что не надо бояться совершать ошибки, мол,

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6188
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6898
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4182
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 2986
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3793
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3803
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6296
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3151
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3445
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7261
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10627
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12349
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13979
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9109
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7064
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5373
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4603
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3412
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3142
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3389
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3011
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Некоторые недокументированные функции Java

Архив номеров / 2003 / Выпуск №3 (4) / Некоторые недокументированные функции Java

Рубрика: Программирование /  Аудит

ДАНИИЛ АЛИЕВСКИЙ

Некоторые недокументированные функции Java

Изучение недокументированных функций в применении к языку Java может показаться несколько странным. Java – грамотный, современный, высоконадежный объектно-ориентированный язык программирования, поставляемый фирмой Sun совместно с обширнейшими библиотеками готовых классов. Неужели в среде Java существуют задачи, которые не решаются с помощью стандартных библиотек и для решения которых имеет смысл прибегать к недокументированным функциям? И что вообще такое «недокументированная функция» в рамках Java?

Слова «недокументированная функция» в случае Java имеют самый прямой смысл. В стандартный комплект поставки языка Java (мы рассматриваем версии 1.4 и выше – Sun Java SDK) входит, помимо документированных пакетов типа java.lang.*, java.util.*, javax.swing.* и т. д. также целый ряд недокументированных пакетов, прежде всего подпакеты sun.* и com.sun.*. Фирма Sun совершенно справедливо рекомендует не пользоваться классами из этих пакетов. Фирма Sun оставляет за собой право в любой момент поменять поведение и даже сам набор этих классов, так что программа, пользующаяся ими, рискует оказаться несовместимой с будущими версиями Java.

На самом деле в подавляющем большинстве ситуаций недокументированные функции, точнее, недокументированные классы из подпакетов sun.* и com.sun.* действительно не нужны. Эти классы в основном обеспечивают низкоуровневую реализацию универсальных классов и интерфейсов, предназначенных для использования в прикладных программах, и почти ничего не добавляют к тем возможностям, которые и так предоставляются стандартными документированными прикладными пакетами.

Из этого правила иногда встречаются исключения.

Автор этой статьи участвовал в разработке сложной системы на языке Java, содержащей более 100 тысяч строк исходного кода. При этом нам лишь несколько раз потребовались недокументированные функции Java. Именно о таких исключениях мне хотелось бы рассказать в данной статье.

Встроенный компилятор JAVA

Наверное, наиболее популярная «недокументированная функция» Java – это компиляция исходных текстов Java в .class-файлы.

Стандартный компилятор javac, входящий в комплект поставки Sun Java SDK, вполне последовательно реализован фирмой Sun на том же самом языке Java в виде сложной иерархии Java-классов. Утилита javac не более чем тривиальная программа, реализованная в машинном коде для всех операционных систем, предназначенная для запуска виртуальной машины Java и обращения к Java-классу, выполняющему собственно компиляцию.

Если ваша программа нуждается в компиляции исходных текстов на языке Java, то наиболее изящное, хотя и недокументированное решение, – воспользоваться стандартным Java-классом фирмы Sun, реализующим такую компиляцию.

На самом деле тут существуют даже два решения – классы sun.tools.javac.Main и com.sun.tools.javac.Main. Оба этих класса находятся в JAR-файле tools.jar, входящем в комплект поставки Sun Java SDK. Этот класс по умолчанию не входит в так называемый Java Runtime Environment (JRE) – набор классов и подкаталогов, который разрешается свободно распространять совместно с вашим Java-приложением для обеспечения его корректного исполнения. Тем не менее лицензионное соглашение фирмы Sun специально разрешает распространять tools.jar в дополнение к JRE совместно с вашими приложениями.

Оба класса – sun.tools.javac.Main и com.sun.tools.ja-vac.Main – хотя и не документированы, но довольно активно обсуждаются на форумах сайта http://java.sun.com.

Первый класс, sun.tools.javac.Main, имеет конструктор:

public Main(

    OutputStream p0,

    String p1)

В качестве параметров конструктор принимает некоторый поток p0, в который будут выдаваться все сообщения компилятора, и некоторую строку неизвестного (автору статьи) назначения; известные мне примеры использования данного класса передавали в качестве p1 строку «javac».

Собственно компиляцию выполняет метод того же класса:

public synchronized boolean compile(

    String[] p0)

Этому методу нужно передать в качестве аргумента массив строк-параметров, которые обычно передаются утилите javac, например:

new String[] {"-d","/путь_к_подкаталогу","myfile.java"}

О результатах компиляции можно узнать из результата метода compile() – в случае успеха он должен вернуть true – или с помощью отдельного метода:

public int getExitStatus()

который в случае успеха должен вернуть 0.

Самая ценная особенность класса sun.tools.javac.Main – возможность указать в конструкторе выходной поток, который будет использоваться для выдачи сообщений об ошибках компилятора. Это дает возможность легко преобразовать этот поток, скажем, в переменную типа String, с тем чтобы самостоятельно ее проанализировать и показать пользователю.

Начиная с версии Sun Java SDK 1.4, объявлен устаревшим класс sun.tools.javac.Main. Попытка явно обратиться к этому классу в программе выдает предупреждение «deprecation warning», а попытка им воспользоваться для компиляции любого класса выдает аналогичное предупреждение в поток ошибок (параметр конструктора p0), если только явно не подавить эти предупреждения ключом «-nowarn» среди параметров метода compile.

Для такого предупреждения есть основания. По крайней мере один из сложных классов, разработанных автором на Java версии 1.4 и прекрасно компилирующихся обычными компиляторами, оказалось невозможным скомпилировать с помощью класса sun.tools.ja-vac.Main. Компилятор вполне явно «сошел с ума» и стал «ругаться» на законные языковые конструкции.

Второй класс, предназначенный для компиляции исходных текстов на Java – единственный «неустаревший» в версии Sun Java SDK 1.4 – это com.sun.tools.ja-vac.Main. Функционально он эквивалентен классу sun.tools.ja-vac.Main, но несколько менее «многословен» в своем наборе методов. Конструктор этого класса не имеет параметров. Методов compile здесь два, причем несинхронизированных, в отличие от sun.tools.javac.Main:

public static int compile(String[] p0)

public static int compile(String[] p0,

    PrintWriter p1)

Второй из этих методов позволяет указать поток вывода, который будет использоваться для вывода всех сообщений компилятора, например:

new PrintWriter(writer=new CharArrayWriter(),true)

Как и в случае sun.tools.javac.Main, второй метод compile позволяет перенаправить поток сообщений компилятора в собственный буфер, с тем чтобы впоследствии превратить его, скажем, в строку типа String для анализа и визуализации.

Класс com.sun.tools.javac.Main в версии Sun Java SDK 1.4 работает существенно быстрее предыдущего класса sun.tools.javac.Main и «справляется» со всеми корректными исходными текстами. Похоже, именно этот класс вызывается изнутри стандартной утилиты javac.

Файлы-ссылки – *.lnk в Microsoft Windows

Второй известный автору случай использования недокументированных функций – распознавание файлов-«ярлыков» (shortcuts) Microsoft Windows, обычно имеющих расширение «.lnk».

Стандартные средства работы с файлами из пакета java.io.* вообще не слишком хорошо «справляются» с файловой системой современных версий Microsoft Windows. Так, стандартный класс java.io.File «понятия не имеет» о том, что корнем файловой иерархии Windows следует считать «Рабочий стол» («Desktop»), у которого есть такие дочерние узлы, как «Мои документы» («My documents») или «Мой компьютер» («My computer»). Стандартный java.io.File по старинке считает корнем иерархии корневой каталог любого дискового устройства.

Чтобы скомпенсировать этот недостаток, не нарушая совместимости с классом File, фирма Sun разработала новый, более современный класс javax.swing.file-chooser.FileSystemView. Он активнейшим образом используется стандартным диалогом выбора файла javax.swing.JFileChooser, что отчасти объясняет несколько странный выбор пакета для FileSystemView.

К сожалению, даже класс FileSystemView не решает всех проблем, по крайней мере, в имеющейся у меня последней версии Sun Java SDK 1.4.1. Современные версии Windows, в частности Windows XP, предлагают пользователю интерфейс, существенно опирающийся на механизм файлов-«ссылок», или «ярлыков». Такими ссылками являются специальные файлы или даже подкаталоги (обычно, но не обязательно с расширением «.lnk»). Щелчок по ним в стандартном Windows Explorer приводит к перемещению в некоторый другой каталог или открытию некоторого другого файла. Именно так в Windows XP организована работа в локальной сети – компьютеры пользователей-«соседей» представлены маленькими виртуальными подкаталогами-«ссылками» в локальной файловой системе текущего пользователя.

Класс FileSystemView не содержит никаких средств для распознавания и обработки подобных ссылок. В результате стандартный диалог выбора файла javax.swing.JFileChooser при использовании в Windows XP производит довольно жалкое впечатление – попытка перейти к компьютерам локальной сети заканчивается позорной неудачей.

В действительности фирма Sun уже реализовала механизм обработки файлов-«ссылок» Microsoft Windows. К сожалению, он пока недокументирован. Это класс sun.awt.shell.ShellFolder. Среди прочих методов, имеющих документированные эквиваленты в классе FileSystemView, класс ShellFolder содержит следующие два метода:

public abstract boolean isLink();

public abstract ShellFolder getLinkLocation()

    throws FileNotFoundException

Вот как можно ими пользоваться:

  public static boolean isLink(File f) {

    try {

      return sun.awt.shell.ShellFolder

        .getShellFolder(f).isLink();

    } catch (FileNotFoundException e) {

      return false;

    }

  }

  public static File getLinkLocation(File f)

    throws FileNotFoundException

  {

    File result= sun.awt.shell.ShellFolder

      .getShellFolder(f).getLinkLocation();

    if (result==null ||

      result.getPath().trim().length()==0)

      throw new FileNotFoundException(

        "Incorrect link - it is empty");

    return result;

  }

Применяя эти методы, при желании можно «исправить» поведение стандартного диалога выбора файла javax.swing.JFileChooser, «научив» его правильно работать с современными локальными сетями Microsoft Windows.

Конечно, будет гораздо лучше, если фирма Sun в очередной версии Java SDK включит в FileSystemView документированные эквиваленты этих методов и исправит javax.swing.JFileChooser. Существование подобных методов в sun.awt.shell.ShellFolder позволяет на это надеяться. Пока же приходится пользоваться недокументированными методами.

Стек вызовов метода

Предположим, нужно получить «трассу стека» – узнать, какой метод исполняется в данный момент, какой метод вызвал этот метод, и т. д. Трудно представить, зачем это может понадобиться, за исключением отладки программы. Однако в реальной практике автору это однажды понадобилось – чтобы выяснить, какие загрузчики классов использовались для загрузки текущего исполняемого кода и всех классов «трассы стека», вызвавших этот код.

Даже для этой столь экзотической ситуации фирма Sun предусмотрела документированную технику. Достаточно возбудить фиктивное исключение, тут же «поймать» его и воспользоваться методом объекта-исключения getStackTrace().

Проблема может заключаться в том, что метод getStackTrace() возвращает исключительно «описательную» информацию о классах и методах «трассы стека» – попросту строковые имена классов и методов. Чтобы получить собственно классы, задействованные в данный момент в стеке (объекты типа Class), необходимо вызвать метод Class.forName или эквивалентный. Но что, если текущий загрузчик классов не в состоянии загрузить такие классы просто по имени? Что, если текущий исполняемый код загружен самым обычным традиционным загрузчиком классов, а класс, который его вызвал – это интернетовский class-файл, загруженный и исполняемый совершенно другим специальным загрузчиком? Тогда метод getStackTrace() никак не поможет «добраться» до этого класса (объекта Class) хотя бы для того, чтобы получить ссылку на загрузивший его загрузчик классов.

В подобной ситуации автору пришлось прибегнуть к недокументированному классу sun.reflect.Reflection, точнее, к его методу.

  public static native Class getCallerClass(int p0)

Вот как выглядит использование этого метода:

  public static Class[] getCurrentStackTraceClasses() {

    List result= new ArrayList();

    for (int count=1; count<10000

      /* страховка на всякий случай */;

      count++)

    {

      Class clazz= sun.reflect.Reflection

        .getCallerClass(count);

      if (clazz==null) break;

      result.add(clazz);

    }

    return (Class[])result.toArray(

      new Class[0]);

  }

Провайдеры сервисов

Сервис-провайдеры (Service provider) – довольно распространенная и неплохо документированная техника среди стандартных библиотек Java. Тем более удивительно, что фирма Sun оставила недокументированным механизм перечисления сервис-провайдеров – класс sun.misc.Service.

Идея сервис-провайдеров вполне очевидна. Допустим, есть некоторый сервис (интерфейс или абстракный класс), предназначенный для использования прикладными программами. Есть также произвольное количество провайдеров – классов, реализующих этот интерфейс или абстрактный класс. Предполагается, что набор провайдеров не фиксирован и может меняться в зависимости от поставки программы. Не исключено, что пользователь может самостоятельно приобрести и инсталлировать в систему дополнительный набор провайдеров какого-либо стандартного сервиса.

Типичный пример применения сервис-провайдеров – разнообразные кодеки, позволяющие читать и писать изображения, аудио или видеозаписи различных форматов. Общая процедура чтения или записи объекта – это сервис, а конкретный кодек, рассчитанный на определенный формат – это провайдер.

Согласно документации, для поддержки сервис-провайдеров нужно положить в подкаталог META-INF/Services некоторого JAR-файла, присутствующего в путях поиска классов Java, специальный текстовый файл. Имя текстового файла должно совпадать с полным именем некоторого сервиса – интерфейса или абстрактного класса, например, «com.pupkin.vasya.My-Service». Этот файл должен содержать (в отдельных строках) список некоторых классов – провайдеров этого сервиса, присутствующих в данном JAR-файле. Тогда система Java сумеет стандартным образом получить этот список в виде набора объектов – экземпляров соответствующих провайдеров. Стандартные библиотеки фирмы Sun примерно так и поступают, когда нужно прочитать изображение или аудиозапись. Почему-то остался недокументированным лишь тот самый стандартный способ, которым извлекается список провайдеров некоторого сервиса.

Этот способ следующий:

  for (Iterator iterator=

    sun.misc.Service.providers(

      класс_сервиса.class);

    iterator.hasNext(); )

  {

    класс_сервиса o= (класс_сервиса)

      iterator.next();

    используем o - экземпляр

      очередного провайдера сервиса;

  }

На самом деле для использования такой техники не обязательно создавать JAR-файл – вполне достаточно разместить правильный подкаталог META-INF в одном из каталогов поиска class-файлов.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru