Abstract
В этой статье описывается архитектура генератора кода на основе шаблонов.
Проект
Этот проект я осуществил, когда работал в InLine Software, она же JFX, она же ObjectVenture. См. Модель-Представление-Характеристика.
Задача
Одним из элементов системы был генератор кода на основе шаблонов.
Сложности
Нашему инструменту необходимо было поддерживать несколько мета-моделей требовавших генерации исходного кода. Среди этих моделей была то, которую мы назвали Extended-J2EE, которая расширила модель программирования J2EE такими понятиями, как Отношение, Событие, Ограничение, Объект-значение и т. д. Другая была абстрактная модель, основанная на Шаблонах дизайна. Каждый шаблон дезайна был реализован с помощью набора шаблонов для генерации кода, а также Характеристик (опять же, см. Модель-Представление-Характеристика. Моя работа заключалась в разработке основы для этой части системы.
Решение
Я разработал язык программирования JCML, который использовался для кодирования шаблонов исходного кода. Шаблон состоял из элементов, привязанных к Features (характеристикам) модели. Плагины могли предоставлять свои дополнения или замены для стандартных шаблонов, которые мы включали в систему. Интерпретатор JCML, который я разработал, разрешал возможные конфликты между различными поставщиками программ для генерации кода и выполнял фактическую генерацию кода. Интерпретатор вызывался реализациями соответствующих Features или FeatureSets.
Вот пример программы на JCML. Это стандартный шаблон для Объекта-значения, который представляет собой обычный JavaBean, который имитирует API EJB EntityBean. Эта программа создает код как для интерфейса так и для его реализации Объекта-значения.
Переменные, упомянутые в шаблоне: className, attributeList и т. д., являются аттрибутами управляющей Feature.
<?xml version="1.0"?>
<jcml package="com.inline.j2ee.enhanced" model="J2EE">
<feature type="ejb1.1-valueObject">
<use-if path="../codeStyle" value="standard"/>
<item name="interface">
<copyright/>
<s-package-declaration>className</s-package-declaration>
import java.io.Serializable;
import java.util.*;
/**
* <s-unqualified-name>className</s-unqualified-name> is an
* object that can hold a data snapshot of the <s>beanName</s>
* EJB.
*
* @author <author/>
* @version <version/>
*/
interface <s-unqualified-name>className</s-unqualified-name>
{
<for var="a" path="attributeList">
<if-equal path="a/included" value="true">
<then>
public <s>a/type</s> <s>a/getterName</s>();
<if-equal path="a/editable" value="true">
<then>
public void <s>a/setterName</s>(
<s>a/type</s> <s>a/name</s>);
</then>
</if-equal>
</then>
</if-equal>
</for>
}
</item>
<item name="implementation">
<copyright/>
<s-package-declaration>implClassName</s-package-declaration>
/**
* <s-unqualified-name>implClassName</s-unqualified-name>
* is an implementation of the ValueObject interface
* <s>className</s>.
*/
public class
<s-unqualified-name>implClassName</s-unqualified-name>
implements <s>className</s>
{
<for var="a" path="attributeList">
<if-equal path="a/included" value="true">
<then>
private <s>a/type</s> <s>a/name</s>;
</then>
</if-equal>
</for>
<for var="a" path="attributeList">
<if-equal path="a/included" value="true">
<then>
public <s>a/type</s> <s>a/getterName</s>() {
return <s>a/name</s>;
}
public void <s>a/setterName</s>(
<s>a/type</s> <s>a/name</s>){
this.<s>a/name</s> = <s>a/name</s>;
}
</then>
</if-equal>
</for>
}
</item>
</feature>
</jcml>
JCML успешно использовался для реализации расширенной модели J2EE, а также шаблонов дизайна. После того, как я оставил Inline/JFX, Билл Уиллис и другие расширили JCML с помощью PCML (языка разметки кода шаблона).
[ПОПРАВКА: февраль 2021 года. В Google я использовал систему шаблонов, которая следует аналогичной парадигме, Google Closure Templates или Soy. См. несколько примеров для сравнения. Я не имел никакого отношения к созданию Soy, просто эта система вызвала воспоминания пятнадцатилетней давности.]
