Условная компиляция Java на основе XML и XSL

Автор: content Понедельник, Апрель 9th, 2012 Нет комментариев

Рубрика: Язык Java

Условная компиляция достаточно полезная вещь, с этим, наверное, никто спорить не будет. Иметь возможность собирать разные версии приложения без изменений исходных текстов очень удобно. Условная компиляция есть в С/С++, в VB и еще наверно не в одном языке программирования. Но ее нет почему-то в Java. Может этому есть разумное объяснение, а может и нет. В любом случае лучше иметь этот инструмент в языке, а уж разработчики сами решат, пользоваться им или нет.

Одним из способов отладки Java (да вообще-то любых) программ, как известно, является добавление в код функций трассировки:

void f(…) {

try {

System.out.println(«job started»);

some_job();

System.out.println(«job OK»);

} catch(…) {

System.out.println(«job FAILED»);

}

}

Когда определенный участок кода отлажен, и необходимость отслеживать его работу пропадает, приходиться избавляться от println-ов вручную. Это неудобно, особенно если учесть, что к отладке придется вернуться еще не один раз, что обычно и происходит. Можно конечно строки не удалять, а просто закрывать их комментариями. Но все равно ручной работы не избежать. Одним словом очень хочется написать на Java что-нибудь вроде такого:

void f(…) {

try {

#ifdef DEBUG

System.out.println(«job started»);

#endif

some_job();

#ifdef DEBUG

System.out.println(«job OK»);

#endif

} catch(…) {

#ifdef DEBUG

System.out.println(«job FAILED»);

#endif

}

}

Но встроенного препроцессора в Java нет, так что это решение не подходит. Есть самодельные препроцессоры. Но ими обычно пользуются сами авторы и их знакомые, но применять их в коммерческих проектах никто, вероятно, не решится. Вот если бы препроцессор был построен на каком-нибудь индустриальном стандарте или написан Sun, тогда другое дело.

Предлагаемый препроцессор как некий исполняемый модуль или отдельный класс-файл не существует. Идея его состоит в том, чтобы представлять исходные java файлы в виде xml документов, а затем трансформировать их в компилируемые java файлы при помощи xsl-процессора и подходящих таблиц стилей.

Следующий пример иллюстрирует работу предложенного препроцессора.

Исходный java файл (Sample.java):

public class Sample {

public static void main(String args[]) {

System.out.println(«start»);

for(int i = 0; i < 5; i++) {

System.out.println(«iteration=» + i);

}

System.out.println(«done»);

}

}

Класс примитивный и в комментариях не нуждается. Псевдокод, приведенный ниже, показывает, какая отладочная информация должна быть удалена из release-версии класса:

public class Sample {

public static void main(String args[]) {

System.out.println(«start»);

for(int i = 0; i < 5; i++) {

#ifdef DEBUG

System.out.println(«iteration=» + i);

#endif

}

System.out.println(«done»);

}

}

Преобразуем псевдокод в xml документ (Sample.java.xml):

<?xml version=»1.0″ encoding=»utf-8″ ?>
<prep:root xmlns:prep=»http://java.preprocessor.ru»> <![CDATA[

public class Sample {

public static void main(String args[]) {

System.out.println(«start»);

for(int i = 0; i < 5; i++) {

// <— ]]> <prep:debug> <![CDATA[

System.out.println("iteration=" + i);

// --> ]]> </prep:debug> <![CDATA[

}

System.out.println("done");

}

}

// ]]> </prep:root>

На приведенном выше листинге представлен xml документ с корневым элементом root. У него есть три дочерних элемента: блок текста, элемент debug и блок текста. В свою очередь элемент debug имеет один дочерний элемент — блок текста. Все элементы принадлежат пространству имен prep (сокращение от preprocessor). Блоки текста ограничиваются парой «» для того чтобы xml процессор не интерпретировал их содержание как xml разметку. Имена элементов root и debug выбраны произвольно, так же как и пространство имен.

Далее необходимо получить из xml документа Sample.java.xml компилируемый java файл. Для этого создадим две таблицы стилей xsl. Одна будет преобразовывать документ Sample.java.xml так чтобы строка System.out.println(«iteration=» + i); оставалась в получаемом java файле, а другая так чтобы эта строка удалялась. Первую таблицу стилей назовем debug.xsl, т.к. после ее применения в выходном java файле останется вся отладочная информация, а вторую release.xsl.

(debug.xsl):

<?xml version=»1.0″ ?<

<xsl:stylesheet version=»1.0″

xmlns:xsl=»http://www.w3.org/1999/XSL/Transform»

xmlns:prep=»http://java.preprocessor.ru»>

<xsl:output method=»text»/>

<xsl:output omit-xml-declaration=»yes»/>

<xsl:output encoding=»utf-8″/>

<xsl:template match=»/»>

<xsl:apply-templates />

</xsl:template>

<xsl:template match=»*|@*|text()»>

<xsl:copy>

<xsl:apply-templates select=»*|@*|text()»/>

</xsl:copy>

</xsl:template>

</xsl:stylesheet>

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

означает, что в результате применения данной таблицы стилей в выходном документа будут удалены элементы разметки xml;
означает, что в выходном документе будет отсутствовать строка ;
значение кодировки выходного документа (строка ) должно совпадать со значением кодировки xml документа к которому будет применена таблица стилей (Sample.java.xml(1):);
кодировка UTF-8 выбрана из-за того, что все xml парсеры и xsl процессоры корректно ее обрабатывают;

Воспользовавшись каким-либо xsl процессором (в данном случае XT):
java com.jclark.xsl.sax.Driver Sample.java.xml debug.xsl Sample.java

получим следующий java файл (Sample.java):

public class Sample {

public static void main(String args[]) {

System.out.println(«start»);

for(int i = 0; i < 5; i++) {

// <—

System.out.println(«iteration=» + i);

// —>

}

System.out.println(«done»);

}

}

//

Как видно из листинга, получился вполне корректный java файл без xml разметки. Следует отметить, что, число строк в оригинальном Sample.java.xml и трансформированном Sample.java файлах одинаковое. Это удобно, т.к. сообщения об ошибках компиляции, выдаваемые javac-ом можно интерпретировать в контексте оригинального Sample.java.xml.

Таблица стилей release.xsl выглядит несколько сложнее:

<?xml version=»1.0″ ?>

<xsl:stylesheet version=»1.0″

xmlns:xsl=»http://www.w3.org/1999/XSL/Transform»

xmlns:prep=»http://java.preprocessor.ru» >

<xsl:output method=»text»/>

<xsl:output omit-xml-declaration=»yes»/>

<xsl:output encoding=»utf-8″/>

<xsl:template match=»/»>

<xsl:apply-templates />

</xsl:template>

<xsl:template match=»text()»>

<xsl:choose>

<xsl:when test=»name(following-sibling::*[1])=’prep:debug’»>

<xsl:copy-of select=»substring(., 0, string-length(.)-7)»/>/***</xsl:when>

<xsl:when test=»name(..)=’prep:debug’»>

<xsl:copy-of select=»substring(., 0, string-length(.)-7)»/>***/</xsl:when>

<xsl:otherwise>

<xsl:copy-of select=».»/>

</xsl:otherwise>

</xsl:choose>

</xsl:template>

</xsl:stylesheet>

Применение release.xsl к Sample.java.xml дает следующий результат (Sample.java):

public class Sample {

public static void main(String args[]) {

System.out.println(«start»);

for(int i = 0; i < 5; i++) {

/***

System.out.println(«iteration=» + i);

***/

}

System.out.println(«done»);

}

}

//

Как видно из листинга Sample.java, отладочная информация оказалась закомментированной, и соответственно не будет компилироваться. Число строк в оригинальном Sample.java.xml и трансформированном Sample.java файлах одинаковое, как и в случае применения debug.xsl.

Т.о. используя различные таблицы стилей xsl можно добиться генерации нескольких java файлов на основе одного xml документа без его изменения.

Приведенные xsl файлы являются простейшими и всего лишь демонстрируют возможности предложенного подхода к построению Java-препроцессора.

В заключение следует сказать несколько слов о xsl процессорах. При разработке (если написание xsl-файлов можно назвать разработкой) препроцессора были испробованы три таких программы:
XT 20020426a http://blnz.com/xt/;
SAXON 6.2.2 http://users.iclway.co.uk/mhkay/saxon/;
XALAN 2.3.1 http://xml.apache.org/xalan-j/index.html.

Все это Java приложения, работают одинаково, но вот с кодировкой «windows-1251″ справился только xalan, два других сказали, что не знают такой и отказались работать.

Источник: http://www.javaportal.ru/java/articles/javapreprocessor.html
Автор: Alexey Semenjuk

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты