Kotlin + Maven toolchain

—

от автора

Главная идея статьи — это показать как заставить ЭТО (kotlin & maven toolchain) работать вместе. Детального описания Maven toolchain здесь не будет, не хочу заниматься банальным переводом руководств.

Начну с прелюдии. Как котлинисту, мне новые версии java как-то по боку, но тут в JDK 22 подъехала годнота — panama/foreign вышла из инкубатора. Для тех кто не в теме, эта фича дает вам возможность вызывать нативный код из ‘динамической библиотеки’ dll/so (прямо из java кода). Теперь вы можете вызывать системные функции сами, а не подключать неизвестные вам библиотеки.

Вкратце о Maven toolchain.

Эта фича позволяет подключать нужную версию jdk (или других инструментов) автоматически. До апреля 2024 года maven toolchain плагин был довольно слабенький (по сравнению с gradle toolchains) — он позволял выбирать toolchain/jdk только из

Но вот недавно (в апреле 2024) подъехала новая версия, которая поддерживает

  • $home/.m2/toolchains.xml файл

  • может подхватывать текущий JDK ($JAVA_HOME), если он удовлетворяет заданным критериям

  • делает поиск в стандартных директориях (например, C:/Program Files/…)

    • Реально прикольная штука, ничего вообще делать не нужно. Проверил на Windows — реально работает. Какое стандартное расположение жабы в Linux — не имею понятия, но можно хотя бы ввести разные JAVA_XXX_HOME (это уже неплохо).

  • делает поиск в переменных окружения по паттерну (например: JAVA11_HOME, JAVA22_HOME). Паттерн конфигурируем.

    • Между прочим, gradle toolchains тоже поддерживают этот подход, но насколько я знаю, переменные нужно добавлять файл проекта вручную.

  • custom toolchains

Сейчас maven toolchain даже немного лучше своего собрата из gradle. В gradle есть неприятный баг по игнорированию vendor (и др атрибутов) из $home/.m2/toolchains.xml, в результате невозможно отличить Oracle (standard) JDK от Oracle Graal JDK.

Перейдем к главному.

У нас всё ещё есть одна проблемка — maven kotlin plugin не дружит с maven toolchain plugin. По крайней мере я не нашел как ему сказать, чтобы он подружился.

Но… у maven kotlin plugin есть конфигурационный параметр jdkHome, который мапится на maven property «toolchain.jdk.version». Это и будет нашим спасением — нужно взять JDK home, найденный toolchain plugin и установить его в соответсвующее свойство. Как по мне решение +- надежное (весь рискованный код помещен в try/catch), но это уже ваш выбор использовать ли его в production, или только в домашнем проекте. В худшем случае, оно просто не будет работать и вы просто вернетесь к старой доброй установке JAVA_HOME.

<project>     ...     <properties>         <!-- Required JDK version in maven-artifact format. -->         <toolchain.jdk.version>[22,)</toolchain.jdk.version>          <!-- Required java-version in numeric format. -->         <java.version>22</java.version>         <java.release>${java.version}</java.release>         <kotlin.version>1.7.0</kotlin.version>         <kotlin.compiler.languageVersion>1.7</kotlin.compiler.languageVersion>          <kotlin.compiler.jvmTarget>15</kotlin.compiler.jvmTarget>         <kotlin.compiler.incremental>true</kotlin.compiler.incremental>          <kotlin-maven-plugin.version>${kotlin.version}</kotlin-maven-plugin.version>     </properties>      <build>         <plugins>             <plugin>               <groupId>org.apache.maven.plugins</groupId>               <artifactId>maven-toolchains-plugin</artifactId>               <version>3.2.0</version>               <executions>                 <execution>                   <goals>                     <goal>select-jdk-toolchain</goal>                   </goals>                 </execution>               </executions>               <configuration>                 <version>${toolchain.jdk.version}</version>                 <!-- Optional old config. Let's keep it to avoid IDEA warning. -->                 <toolchains>                   <jdk>                     <version>${toolchain.jdk.version}</version>                   </jdk>                 </toolchains>               </configuration>             </plugin>                          <plugin>               <groupId>org.codehaus.mojo</groupId>               <artifactId>build-helper-maven-plugin</artifactId>               <version>3.4.0</version>               <executions>                 <execution>                   <id>use-maven-toolchain-jdk-for-kotlin</id>                   <goals>                     <goal>bsh-property</goal>                   </goals>                   <configuration>                     <source><![CDATA[                       import org.apache.maven.plugin.descriptor.PluginDescriptor;                                    String toolChainJdk = null;                                    try {                         PluginDescriptor pd = new PluginDescriptor();                         pd.setGroupId("org.apache.maven.plugins");                         pd.setArtifactId("maven-toolchains-plugin");                                      Map pluginContext = session.getPluginContext(pd, project);                         if (pluginContext == null)                           throw new IllegalStateException("maven-toolchains-plugin plugin context is not found. Probably it is not set up.");                                      // A bit risky part of code: I'm not 100% sure that this class will be used in the future.                         // It is not specified in the org.apache.maven.model.ConfigurationContainer                         // (there is just java.lang.Object, but it must be some DOM)                                      Object toolchainPluginContext = pluginContext.get("toolchain-jdk");                         if (toolchainPluginContext != null) {                           // We can use type Object in bean-shell script instead of Xpp3Dom.                           // Real type is XML DOM object (currently type is org.codehaus.plexus.util.xml.Xpp3Dom class)                                        Object config = toolchainPluginContext.getConfiguration();                           if (config != null && config.getChildCount() > 0)                             toolChainJdk = config.getChild(0).getValue().trim();                         }                       } catch (Exception ex) {                         log.error("toolchain-jdk is not found. " + ex.getMessage(), ex);                                      // Or we can rethrow error just there.                         // throw new IllegalStateException("toolchain-jdk is not found.", ex);                       }                                    String requiredJdkVersion = project.getProperties().getProperty("toolchain.jdk.version");                       if (toolChainJdk != null && !toolChainJdk.isEmpty()) {                         project.getProperties().setProperty("kotlin.compiler.jdkHome", toolChainJdk);                                      log.info("toolchain-jdk for version '" + requiredJdkVersion + "' is " + toolChainJdk);                         log.info("It will be used for kotlin compiler");                       }                       else {                         String currentJavaHome = System.getProperty("java.home");                                      log.info("toolchain-jdk for version '" + requiredJdkVersion + "' is not found.");                         log.info("  Possible reasons");                         log.info("    * default java_home matches required java version ");                         log.info("    * maven-toolchains-plugin is not configured properly");                         log.info("  ");                         log.info("Default " + currentJavaHome + " will be used.");                       }                                    ]]>                     </source>                   </configuration>                 </execution>               </executions>             </plugin>                  </plugins>     </build> </project> 

Полные исходники на github

Полезные ссылки


ссылка на оригинал статьи https://habr.com/ru/articles/811787/


Комментарии

Добавить комментарий

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