JDK 1.6: что принесет очередное обновление

15 ноябрь, 2006 - 17:21Виктор Вейтман

Прошло два года с тех пор, как компания Sun Microsystems выпустила платформу JDK 1.5, и сейчас мы находимся в ожидании ее следующего релиза. Впрочем, больших секретов из него никто не делает: бета-версии JDK 1.6 различной степени готовности доступны уже почти полгода. Конечно же, новшества не идут ни в какое сравнение с «революционными преобразованиями» JDK 1.5, и тем не менее некоторые тенденции обращают на себя внимание, и заинтересованным разработчикам есть над чем поразмыслить.

Программа и сценарий работают вместе

Если кто-то захочет подсчитать, сколько раз в печати встречалось предложение: «JavaScript – не Java!», ему придется изрядно потрудиться. С такой сентенции начинались многие статьи, посвященные популярному языку сценариев. Однако с появлением JDK 1.6 утверждать это столь категорично уже нельзя, потому что в данной платформе впервые нашла свое воплощение JSR 223, а значит, появилась возможность интегрировать программы на Java со сценариями, написанными на JavaScript.

Средства для работы со сценариями сосредоточены в пакете javax.script. Его основой является интерфейс ScriptEngine – именно его реализует класс, обеспечивающий выполнение сценария. Пока интерпретатор только один – Mozilla Rhino, ориентированный на JavaScript, но в дальнейшем планируется поддержка и других языков. В принципе экземпляры интерпретаторов могут быть построены с помощью соответствующего конструктора, но для тех из них, что реализованы в составе JDK, гораздо проще вызвать один из методов класса ScriptEngineManager – при этом достаточно указать его имя, расширение файла или MIME-тип.

Каждому интерпретатору соответствует класс ScriptEngineFactory, обеспечивающий вспомогательные функции. На данный момент (пока речь идет только о JavaScript) разработчика могут заинтересовать разве что методы getOutputStatement() и getProgram(), но применимость ScriptEngineFactory существенно возрастет, когда будут поддерживаться и другие языки.

На первый взгляд может показаться, что пакет javax.script дает возможность управлять HTML-документом из апплета. Увы, это не так. Сценарий, включенный в состав HTML-кода, выполняется под управлением другого интерпретатора, отличного от класса, реализующего интерфейс ScriptEngine. Поэтому в Java-программе недоступны предопределенные объекты window, document и другие, которые и создают условия для манипулирования элементами Web-страницы. Таким образом, нельзя не признать, что на стороне Web-клиента средства взаимодействия со сценариями, поддерживаемые в JDK 1.6, имеют довольно ограниченное применение. Однако на стороне сервера открываются широчайшие возможности для творчества. Прежде всего классы и интерфейсы из пакета javax.script позволяют использовать в разрабатываемой программе ранее созданные сценарии. И хотя серверного кода на JavaScript не так уж много, нужно помнить, что в перспективе будут поддержаны и другие языки. Из этих соображений, по-видимому, было бы целесообразно в первую очередь обратить внимание на PHP, поскольку эта технология сегодня одна из наиболее популярных.

Взаимодействие Java-программ и JavaScript-кода – двухстороннее. Можно не только вызывать сценарии из программы, написанной на Java, но и обращаться к классам и методам Java из сценария. Это пригодится, например, если разработчик не уверен в том, правильно ли он понял работу класса или метода из документации и ему требуется эксперимент с реальным кодом. Используя интерпретируемый язык, такое исследование можно провести значительно быстрее, чем путем написания программы на Java. Необходимость создания пробных фрагментов кода «одноразового использования» возникает значительно чаще, чем может показаться непосвященному. Недаром для обозначения подобной деятельности существует даже специальный термин: exploratory programming – экспериментирование, позволяющее лучше понять ту или иную программную среду. Для этих целей в состав JDK 1.6 входит специальный инструмент jrunscript – интерпретатор JavaScript, обеспечивающий доступ к пакетам и классам Java.

Предположим, разработчика интересует, присутствуют ли еще в классе JFrame методы show() и hide() (как известно, они не рекомендованы к применению и их поддержка может быть прекращена в любой момент; на замену им создан метод setVisible()).Чтобы выяснить реальное положение вещей, достаточно запустить консоль jrunscript, импортировать пакет javax.swing (с помощью importPackage()), создать в интерактивном режиме фрейм, а затем в командной строке вызвать методы show() и hide(), обращая внимание на результаты. Вся процедура вместе с вызовом jrunscript и чтением справочной информации занимает 2–3 мин, написание и компиляция проверочной Java-программы потребуют больше времени даже в такой элементарной ситуации.

Приведенные примеры иллюстрируют лишь малую часть возможных применений новых средств взаимодействия с языками сценариев, реализованных в JDK 1.6. Область их использования ограничивается лишь фантазией разработчика.

И снова потоки

Язык Java как никакой другой богат потоками (streams). Программисты уже привыкли к тому, что, помимо «тривиальных» байтовых и символьных, в их распоряжение предоставляются потоки для поддержки разнообразных типов данных и даже такие «экзотические», как для работы с файлами архивов. Тем не менее разработчики JDK 1.6 не остановились на этом. В частности, они реализовали потоки для формирования XML-документов (интерфейс XMLStreamWriter) и их разбора (интерфейс XMLStreamReader). Но если создание архивов полностью автоматизировано, то XML-файл, к сожалению, не удается сгенерировать по мановению руки. Это вполне понятно: структура XML-документа не определена жестко, элемент может иметь любое имя и произвольный набор атрибутов, а в какой элемент следует поместить те или иные данные, знает только сам разработчик. Поэтому элемент надо явным образом создать, вызвав метод writeEmpty Element() класса, реализующего XMLStreamWriter, включить в открывающий дескриптор атрибуты (writeAttribute()), организовать запись (writeCData() и writeCharacters()) и даже закрыть (writeEnd Element()). Таким образом, нагрузка на программиста, создающего XML-документ, несколько снижается, но не сводится к нулю, как в случае с архивами. Например, метод writeNamespace() упрощает работу с пространствами имен, но не избавляет от необходимости иметь четкое представление о них.

Разбор документа, в отличие от его формирования, не так просто осуществить вручную, и тут класс, реализующий интерфейс XML-StreamReader, оказывается как нельзя кстати. В XMLStreamReader объявлены методы, позволяющие совместить чтение из потока с синтаксическим разбором документа средствами SAX. В этом процессе используется курсор, который перемещается от начала к концу документа. В каждый момент времени он указывает на реальный объект, к примеру, начало документа, открывающий дескриптор XML-элемента, атрибут, закрывающий дескриптор. В зависимости от его конкретного положения можно использовать те или иные get-методы: getName(), getLocalName(), getNamespaceURI(), getText(), getAttributeCount(), getAttributeName(), getAttributeValue() и многие другие, обеспечивающие работу с именами элементов, их содержимым, атрибутами и т. д. А чаще всего, конечно же, вызываются методы next(), перемещающий курсор к следующему объекту, и hasNext(), позволяющий определить, есть ли еще объекты для разбора или достигнут конец документа.

Читатели с опытом работы с XML-документами наверняка заметят, что аналогичные результаты можно было получить и раньше имеющимися в наличии инструментами SAX-разбора. В новой версии эти же средства оформлены в виде потоков, а для описания данного подхода был даже введен термин StAX – Streaming API for XML. Кроме того, несколько изменились взаимоотношения анализатора и остальных компонентов приложения. Ранее в процессе разбора XML центральное место занимал анализатор, который сообщал приложению о том, что интересующая его порция документа подготовлена к работе. Средства StAX «оттеснили» его на второй план – теперь он терпеливо дожидается от приложения запроса на получение очередного объекта. Хорошо это или нет – решать разработчикам. По крайней мере, старые инструменты по-прежнему доступны, и каждый программист волен сам выбрать наиболее подходящую технологию.

XML-автограф

Говоря о новых возможностях, реализованных в JDK 1.6, нельзя не упомянуть средства цифровой подписи, содержащиеся в javax.xml.crypto и вложенных в него пакетах. Подписываемые данные – это не обязательно XML-документ, как может показаться на первый взгляд. В XML-формате представляется лишь сама подпись, а заверять ею можно произвольный ресурс, в том числе фрагмент текущего XML-файла и даже информацию, не имеющую к нему ни малейшего отношения.

Для того чтобы с помощью средств JDK 1.6 создать в составе XML-файла элемент (т. е. цифровую подпись), следует выполнить специальную процедуру. Она не очень сложна, но все же предполагает более десяти действий, основная часть которых производится посредством объекта XMLSignatureFactory: это выбор способа формирования дайджеста (метод newDigestMethod()), создание объекта Reference, указывающего на ресурс, который должен быть заверен, выбор алгоритма создания подписи (newSignatureMethod()) и, наконец, создание объекта XMLSignature, посредством которого она и формируется.

Если при передаче двоичной информации в нее нельзя вносить даже минимальные изменения, то с XML-файлами дело обстоит совершенно иначе. Одни и те же данные могут быть представлены в формате XML по-разному; например, лишний пробел в большинстве случаев не оказывает никакого влияния на интерпретацию информации. Чтобы различия в документах одинакового содержания не проявлялись, предусмотрены разные способы приведения данных к каноническому виду. Конкретный способ описывается объектом CanonicalizationMethod, для выбора которого опять же используется объект XMLSignatureFactory (метод newCanonicalizationMethod()).В ряде случаев такая процедура является обязательной.

Кроме того, в состав должен входить элемент , содержащий информацию об алгоритмах приведения к каноническому виду и создания подписи, а также список ссылок на заверяемые ресурсы. Его формирование также осуществляется с помощью объекта XMLSignatureFactory (метод newSignedInfo()).

Остальные действия по подготовке подписи сводятся к работе с контекстом, информацией о ключе и способом преобразования. Конкретный их набор зависит от того, заверяется ли подписью внешний ресурс (detached), помещается ли она в одном файле с данными (enveloped) или же содержит их внутри себя (enveloping). И, наконец, «завершающий аккорд» – вызов метода sign() объекта XMLSignature, при выполнении которого и создается элемент .

Конечно, сам принцип XML-подписи не имеет никакого отношения к технологии Java, он был сформулирован специалистами W3C еще в начале 2002 г. Разработчики JDK 1.6 лишь реализовали в рамках API инструментальные средства для его поддержки, упростив тем самым решение ряда задач, возникающих при создании приложений.

Компиляция из программы

Как быть, если разработчик сталкивается с необходимостью организовать генерацию одного или нескольких классов в процессе выполнения программы? Причем, что называется, «с нуля» – т. е. сформировать исходный Java-код, произвести компиляцию, затем загрузить и выполнить полученный файл класса? Нельзя сказать, что такая проблема встает перед каждым вторым программистом, но ведь инструменты разработки должны быть ориентированы не только на выполнение рутинных функций. Еще недавно задачи динамического создания классов были, как говорится, «из области фантастики», однако в последнее время предпринимаются шаги для их решения. Сначала появилось дополнение к спецификации JSR 199, содержащее требования к API для работы с компилятором, а в JDK 1.6 уже сделана попытка воплощения изложенных в нем требований. Увы, на сегодняшний день это именно попытка. В пакете javax.tools определен интерфейс JavaCompilerTool, который должны реализовывать компиляторы, доступные из Java-программ. Там же содержится и класс ToolProvider, способный предоставлять экземпляр такого компилятора. Но пока на этом все и заканчивается. В бета-версии JDK 1.6 для Windows статический метод defaultJavaCompiler() класса ToolProvider вместо ссылки на конкретный объект упорно возвращает значение null. Несколько лучше ситуация на других платформах, но и там не все гладко. Специалисты, пытающиеся освоить новые возможности, жалуются на несоответствие методов и классов спецификации. Остается лишь надеяться, что в финальном релизе при работе с классами и интерфейсами из пакета javax.tools подобные проблемы возникать не будут.

К сожалению, в одной статье невозможно даже вкратце рассмотреть все новшества, которые обнаружат разработчики в JDK 1.6. Так, мы не касались элементов JDBC 4.0 и дополнительных методов в интерфейсах из пакета javax.sql, средств управления, в частности классов из java.lang.management и утилит, предназначенных для мониторинга. Кроме того, во многих классах появились методы, расширяющие их возможности и упрощающие работу программистов и, конечно же, ряд функций API претерпел изменения, не затрагивающие самого интерфейса, но повышающие производительность работы программ. Впрочем, согласно нынешним планам Sun Microsystems, JDK 1.6 должна появиться уже в декабре, поэтому вскоре все заинтересованные смогут заняться ее изучением самостоятельно и более подробно.