Допустим отдел аналитики подготовил нам Swagger YAML с описанием API доступа к какому-то сервису: xyz-swagger-v1.0.0.yaml.
Как автоматизировать генерацию библиотеки для доступа к API по этому описанию, если у вас maven? Полного мануала почему-то нигде нет, так что я собрал в одну всю информацию о реализации и возможных проблемах.
Для генерации нам понадобятся следующие плагины для maven:
-
maven-clean-plugin — удаляет файлы. Он нужен, чтобы очистить директорию с исходниками проекта от предыдущей сгенерированной версии. Настройки, на которые следует обратить внимание:
configuration.filesets.fileset.directory: ${project.basedir}/src/main/java — мы будем очищать директорию самого приложения
configuration.filesets.fileset.includes.include: ** — не только очищать директорию /src/main/java, но и удалять её саму.
-
openapi-generator-maven-plugin — генерирует по OpenAPI YAML для Swagger Java-классы. Настройки, на которые следует обратить внимание:
apiPackage — пространства имён для классов сервисов API
modelPackage — пространства имён для классов моделей
output: ${project.basedir} — если настроить его так, сгенерированные файлы падали не в target, а прямо в папку с кодом
Сгенерированные файлы используют аннотации и методы из внешних библиотек. Поэтому в dependencies нужно будет добавить:
spring-boot-starter-web версии 2.4.4
spring-data-jpa версии версии 2.4.6
jackson-databind-nullable версии 0.2.6
springdoc-openapi-ui версии 1.8.0
Если какой-то из этих версий нет в доступных вашему проекту репозиториях — используйте те, которые доступны. Но увеличивайте версию осторожно и перепроверяйте после каждого изменения: как минимум spring-boot-starter-web и spring-data-jpa не совсем обратно совместимы и при повышении их версии в сгенерированных файлах может перестать распозновать зависимости.
Создайте пустой проект с поддержкой Maven и удалите весь код из папки java.
Поместите в папку /src/main/resources/ файл с YAML-описанием OpenAPI для Swagger. В моём примере это xyz-swagger-v1.0.0.yaml
В результате pom.xml будет выглядеть примерно как-то так:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.mycompany</groupId>
<artifactId>xyz-api-service</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot-starter-web.version>2.4.4</spring-boot-starter-web.version>
<spring-data-jpa.version>2.4.6</spring-data-jpa.version>
<jackson-databind-nullable.version>0.2.6</jackson-databind-nullable.version>
<springdoc-openapi-ui.version>1.8.0</springdoc-openapi-ui.version>
<openapi-generator-maven-plugin.version>7.1.0</openapi-generator-maven-plugin.version>
<maven-clean-plugin.version>2.4.1</maven-clean-plugin.version>
<swagger-yaml>xyz-swagger-v${swagger-yaml.version}.yaml</swagger-yaml>
<swagger-yaml.version>1.0.0</swagger-yaml.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot-starter-web.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>${springdoc-openapi-ui.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/src/main/java</directory>
<includes>
<include>**</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>${openapi-generator-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/${swagger-yaml}</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>org.mycompany.xyz.api</apiPackage>
<modelPackage>org.mycompany.xyz.model</modelPackage>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate
<configOptions>
<delegatePattern>true</delegatePattern>
</configOptions>
<output>${project.basedir}</output>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
При обновлении версии файла будет достаточно заменить свойство swagger-yaml.version. А формат имени файла указывается в свойстве swagger-yaml.
Чтобы сгенерировать файлы, просто выполните из консоли или интерфейса вашей IDE две команды жизненного цикла Maven: clean и compile.
И сгенерированные файлы появятся прямо в рабочей директории. При новой генерации старые файлы будут удаляться автоматически
Важно: не пытайтесь запускать указанные плагины напрямую. Напрямую они просто не будут работать.
Небольшой штришок — чтобы не мусорить в репозитории, нужно добавить в .gitignore (для Git, в Mercurial этот файл называется .hgignore) пометку о том, что нужно игнорировать временные файлы, которые создаёт плагин:
.openapi-generator
Pr1st
Указывать в clean плагине "configuration.filesets.fileset.directory: ${project.basedir}/src/main/java" это кончно сильно
Для незнающих, хороший совет: не указывайте в плагинах генерирующие ресуры (например openapi-generator-maven-plugin) "src", нужно указывать специально для этого спроектированную "target/generated-sources" и clean плагин не надо будет кастомизировать.
Подробнее есть например в ответе тут: https://stackoverflow.com/questions/21340508/how-can-i-organize-source-generation-in-maven