Статьи

Взломать скорость в свой собственный генератор кода

Speedment — это набор инструментов с открытым исходным кодом, который можно использовать для создания сущностей и менеджеров Java для связи с базой данных. Это замечательно, если вам нужно объектно-реляционное отображение модели предметной области, но в некоторых случаях вы можете сгенерировать что-то совершенно другое, используя вашу базу данных в качестве шаблона. В этой статье я собираюсь показать вам хак, который вы можете использовать, чтобы захватить этот генератор кода в Speedment и использовать его в своих личных целях. В конце статьи у нас будет полностью пустой генератор кода, который мы можем запрограммировать для выполнения наших торгов!

Фон

Speedment предназначен для работы в качестве плагина к Maven. Используя различные новые цели Maven, мы можем указать Speedment подключиться к базе данных, сгенерировать исходный код, а также удалить все сгенерированные файлы из нашего проекта. Он также содержит графический интерфейс пользователя, который упрощает настройку задания генерации на основе метаданных, собранных из нашей базы данных. Теперь представьте всю эту информацию, которую мы можем собрать, проанализировав эти метаданные. Мы знаем, какие таблицы существуют, мы знаем обо всех ограничениях, которые у них есть, и какие типы имеют отдельные столбцы. Вероятно, существуют миллионы вариантов использования, в которых мы можем извлечь выгоду из автоматического создания материала из этих метаданных. Следуя инструкциям в этой статье, мы можем сделать все это.

tool_gui_ready_to_generate

Шаг 1: Настройте Проект Регулярного ускорения

Создайте новый проект Maven и добавьте в файл pom.xml следующее:

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<properties>
    <speedment.version>3.0.1</speedment.version>
    <mysql.version>5.1.39</mysql.version>
</properties>
 
 
<dependencies>
    <dependency>
        <groupId>com.speedment</groupId>
        <artifactId>runtime</artifactId>
        <version>${speedment.version}</version>
        <type>pom</type>
    </dependency>
</dependencies>
 
 
<build>
    <plugins>
        <plugin>
            <groupId>com.speedment</groupId>
            <artifactId>speedment-maven-plugin</artifactId>
            <version>${speedment.version}</version>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>${mysql.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

Мы добавили Speedment в качестве зависимости времени выполнения и настроили плагин Maven для использования стандартного драйвера JDBC MySQL для подключения к нашей базе данных. Большой! Теперь у вас есть доступ к ряду новых целей Maven. Например, если мы хотим запустить пользовательский интерфейс Speedment, мы можем сделать это, выполнив:

1
mvn speedment:tool

Если бы мы сделали это сейчас, Speedment запустился бы в обычном режиме, позволяя нам подключаться к базе данных и из нее генерировать сущности и менеджеров для связи с этой базой данных, используя потоки Java 8. Это не то, что мы хотим сделать в этот раз. Мы хотим взломать его, чтобы он делал именно то, что нам нужно. Поэтому мы продолжаем модифицировать пом.

Шаг 2: Изменить объявление плагина

Ускорение построено по модульному принципу с различными артефактами, отвечающими за различные задачи. Все ранее существующие задачи генератора находятся в артефакте, который называется «com.speedment.generator: generator-standard». Вот где мы собираемся нанести удар! Удаляя этот артефакт из пути к классам, мы можем предотвратить создание Speedment того, что нам не нужно.

Мы модифицируем пом следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
<plugin>
    <groupId>com.speedment</groupId>
    <artifactId>speedment-maven-plugin</artifactId>
    <version>${speedment.version}</version>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        
        <!-- Add this: -->
        <dependency>
            <groupId>com.speedment</groupId>
            <artifactId>tool</artifactId>
             <version>${speedment.version}</version>
             <type>pom</type>
             <exclusions>
                 <exclusion>
                     <groupId>com.speedment.generator</groupId>
                     <artifactId>generator-standard</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</plugin>
...

Что это? Мы исключаем зависимость, добавляя одну? Как это может даже работать? Что ж, Speedment разработан так, чтобы включать как можно меньше кода, если это явно не требуется приложению. «Com.speedment: tool-artifact» уже является зависимостью от плагина maven, и, упомянув его в разделе <dependencies> плагина maven, мы можем добавить настройки в его конфигурацию. В этом случае мы говорим, что хотим, чтобы плагин имел доступ к инструменту, за исключением того, что нам не нужен стандартный генератор.

Здесь есть проблема, хотя. Если мы попытаемся запустить инструмент speedment: цель, мы получим исключение. Причина этого в том, что Speedment ожидает, что стандартные переводчики будут на пути к классам.

Вот где приходит второй уродливый взлом. В нашем проекте мы создаем новый пакет с именем com.speedment.generator.standard и в нем определяем новый файл Java с именем StandardTranslatorBundle.java. Оказывается, это единственный файл, который Speedment действительно должен работать. Мы даем ему следующее содержание:

StandardTranslatorBundle.java

01
02
03
04
05
06
07
08
09
10
11
12
13
package com.speedment.generator.standard;
 
 
import com.speedment.common.injector.InjectBundle;
import java.util.stream.Stream;
 
 
public final class StandardTranslatorBundle implements InjectBundle {
    @Override
    public Stream<Class<?>> injectables() {
        return Stream.empty();
    }
}

Затем нам нужно заменить исключенный артефакт нашим собственным проектом, чтобы плагин никогда не осознавал, что файлы отсутствуют. Мы возвращаемся в файл pom.xml и добавляем наш собственный проект в раздел <dependencies> speedment-maven-plugin. Полный файл POM выглядит следующим образом:

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="UTF-8"?>
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
     
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.github.pyknic</groupId>
  <artifactId>speedment-general-purpose</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>jar</packaging>
     
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <speedment.version>3.0.1</speedment.version>
  </properties>
     
  <dependencies>
    <dependency>
      <groupId>com.speedment</groupId>
      <artifactId>runtime</artifactId>
      <version>${speedment.version}</version>
      <type>pom</type>
    </dependency>
  </dependencies>
     
  <build>
    <plugins>
      <plugin>
        <groupId>com.speedment</groupId>
        <artifactId>speedment-maven-plugin</artifactId>
        <version>${speedment.version}</version>
        <dependencies>
          <dependency>
            <groupId>com.speedment</groupId>
            <artifactId>tool</artifactId>
            <version>${speedment.version}</version>
            <type>pom</type>
            <exclusions>
              <exclusion>
                <groupId>com.speedment.generator</groupId>
                <artifactId>generator-standard</artifactId>
              </exclusion>
            </exclusions>
          </dependency>
          <dependency>
            <groupId>com.github.pyknic</groupId>
            <artifactId>speedment-general-purpose</artifactId>
            <version>1.0.0-SNAPSHOT</version>
          </dependency>  
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</project>

Если мы сейчас создадим наш проект и затем запустим инструмент target speedment: мы сможем без проблем запустить графический интерфейс пользователя. Если мы подключимся к базе данных и нажмем «Сгенерировать», ничего не произойдет! Мы успешно взломали Speedment и сделали абсолютно ничего!

Шаг 3: Превратите скорость в то, что вы хотите, чтобы она была

Теперь, когда у нас есть свежий, чистый Speedment, мы можем начать превращать его в приложение, которым мы хотим его видеть. У нас все еще есть мощный пользовательский интерфейс, в котором мы можем настроить генерацию кода на основе модели базы данных. У нас есть выразительная библиотека утилит и вспомогательных классов для работы с сгенерированным кодом. И, прежде всего, у нас есть структура для анализа метаданных базы данных объектно-ориентированным способом.

Чтобы узнать больше о том, как написать свои собственные шаблоны генерации кода и подключить их к платформе, ознакомьтесь с этой статьей . Вам также следует посетить страницу Speedment GitHub, чтобы узнать, как работают существующие генераторы (те, которые мы только что отключили) и, возможно, получить вдохновение о том, как вы можете создать свой собственный.

До следующего раза, продолжайте взламывать!

Ссылка: Добейтесь успеха в своем личном генераторе кода от нашего партнера JCG Эмиля Форслунда из блога Age of Java .