JCML: язык шаблонов кода на Java

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, просто эта система вызвала воспоминания пятнадцатилетней давности.]

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *