Генерация кода — это распространенный способ уменьшить нездоровую нагрузку на скучные задачи, которые часто возлагаются на нас. Многие фреймворки генерации кода, которые я видел, используют подход шаблона-замены-повторения, где вы пишете шаблон для того, как должен выглядеть сгенерированный файл кода, а затем заменяете определенные ключевые слова и повторяете другие разделы, чтобы получить нужный файл.
Проблема с этим подходом, который меня раздражает, состоит в том, что действительно трудно знать, будет ли сгенерированный код работать или нет, пока вы не скомпилируете его. Возможно, вы изменили имя одного класса, и вдруг сгенерированный код не будет создан. Чтобы справиться с этой проблемой, я запустил проект под названием CodeGen, который стремится быть полностью объектно-ориентированным, чтобы вы могли извлечь выгоду из безопасности типов на всем пути от шаблона до исполняемого кода. Основным примером использования генератора является программное обеспечение Speedment , но оно может использоваться в различных проектах.
Рассмотрим следующий код:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
 | 
final Generator generator = new JavaGenerator();final File file = File.of("org/example/Foo.java")    .add(Class.of("Foo").public_()        .add(Field.of("x", DOUBLE_PRIMITIVE).final_())        .add(Field.of("y", DOUBLE_PRIMITIVE).final_())        .add(Field.of("z", DOUBLE_PRIMITIVE).final_())        .call(new AutoConstructor())        .call(new AutoSetGetAdd())        .call(new AutoEquals())    )    .call(new AutoJavadoc())    .call(new AutoImports(generator)); | 
Дерево модели приложения построено с использованием bean-компонентов. Новые методы и переменные-члены могут быть добавлены в дерево для создания вариантов того же класса.
Когда код должен отображаться, его можно легко передать классу генератора.
| 
 1 
 | 
String code = generator.on(file).get(); | 
Сгенерированный код будет выглядеть следующим образом:
| 
 001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
058 
059 
060 
061 
062 
063 
064 
065 
066 
067 
068 
069 
070 
071 
072 
073 
074 
075 
076 
077 
078 
079 
080 
081 
082 
083 
084 
085 
086 
087 
088 
089 
090 
091 
092 
093 
094 
095 
096 
097 
098 
099 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
 | 
/** * Write some documentation here. */package org.example;import java.util.Optional;/** * @author You name here */public class Foo {    private final double x;    private final double y;    private final double z;    /**     * Initializes the Foo component.     *     * @param x  the x     * @param y  the y     * @param z  the z     */    public Foo(double x, double y, double z) {        this.x = x;        this.y = y;        this.z = z;    }    /**     * Returns the value of x.     *     * @return  the value of x     */    public double getX() {        return x;    }    /**     * Sets a new value for x.     *     * @param x  the new value of x     */    public void setX(double x) {        this.x = x;    }    /**     * Returns the value of y.     *     * @return  the value of y     */    public double getY() {        return y;    }    /**     * Sets a new value for y.     *     * @param y  the new value of y     */    public void setY(double y) {        this.y = y;    }    /**     * Returns the value of z.     *     * @return  the value of z     */    public double getZ() {        return z;    }    /**     * Sets a new value for z.     *     * @param z  the new value of z     */    public void setZ(double z) {        this.z = z;    }    /**     * Generates a hashCode for this object. If any field is     * changed to another value, the hashCode may be different.     * Two objects with the same values are guaranteed to have     * the same hashCode. Two objects with the same hashCode are     * not guaranteed to have the same hashCode."     *     * @return  the hash code     */    @Override    public int hashCode() {        int hash = 7;        hash = 31 * hash + (Double.hashCode(this.x));        hash = 31 * hash + (Double.hashCode(this.y));        hash = 31 * hash + (Double.hashCode(this.z));        return hash;    }    /**     * Compares this object with the specified one for equality.     * The other object must be of the same type and not null for     * the method to return true.     *     * @param other  the object to compare with     * @return  {@code true} if the objects are equal     */    @Override    public boolean equals(Object other) {        return Optional.ofNullable(other)            .filter(o -> getClass().equals(o.getClass()))            .map(o -> (Foo) o)            .filter(o -> this.x == o.x)            .filter(o -> this.y == o.y)            .filter(o -> this.z == o.z)            .isPresent();    }} | 
Каждый компонент реализован в виде пары интерфейс-класс, так что вы можете динамически изменять реализацию, не переписывая другие части системы.
Надеюсь, это будет полезно для других людей!
| Ссылка: | Объектно-ориентированный подход к генерации кода от нашего партнера JCG Эмиля Форслунда из блога Age of Java . |