Kotlin + Maven toolchain

50f9daf73ead249336186c98c355c55f

Главная идея статьи — это показать как заставить ЭТО (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.


    ...
    
        
        [22,)

        
        22
        ${java.version}
        1.7.0
        1.7

        15
        true

        ${kotlin.version}
    

    
        
            
              org.apache.maven.plugins
              maven-toolchains-plugin
              3.2.0
              
                
                  
                    select-jdk-toolchain
                  
                
              
              
                ${toolchain.jdk.version}
                
                
                  
                    ${toolchain.jdk.version}
                  
                
              
            
            
            
              org.codehaus.mojo
              build-helper-maven-plugin
              3.4.0
              
                
                  use-maven-toolchain-jdk-for-kotlin
                  
                    bsh-property
                  
                  
                     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.");
                      }
            
                      ]]>
                    
                  
                
              
            
        
        
    

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

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

© Habrahabr.ru