Прочитать записи пути Java в проекте Maven

У меня есть проект, который имеет зависимости в своем пути к классам (путь построения Java). Теперь я преобразовал его в проект maven и скомпилировал его, используя мой настраиваемый плагин Maven. Следующим будет мой файл POM -

<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>com.test</groupId>
  <artifactId>test</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>ear</packaging>


  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
      <plugins>
         <plugin>
            <groupId>com.my.maven.plugin</groupId>
            <artifactId>my-maven-plugin</artifactId>
            <version>0.0.1</version>
            <extensions>true</extensions>
         </plugin>
      </plugins>
  </build>
</project>

И в my-maven-plugin у меня есть переопределенная фаза компиляции -

maven-plugin pom-

    <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>com.test</groupId>
  <artifactId>my-maven-plugin</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>maven-plugin</packaging>

  <name>my-maven-plugin</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-core</artifactId>
        <version>3.3.9</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.3.9</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-compat</artifactId>
      <version>3.3.9</version>
    </dependency>   
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-embedder</artifactId>
      <version>3.3.9</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-archiver</artifactId>
      <version>2.5</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.5</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.4</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>maven-surefire-common</artifactId>
      <version>2.19.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.surefire</groupId>
      <artifactId>surefire-api</artifactId>
      <version>2.19.1</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.plexus</groupId>
        <artifactId>plexus-component-annotations</artifactId>
        <version>1.6</version>
        <exclusions>
            <exclusion>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
       <groupId>org.apache.maven.surefire</groupId>
       <artifactId>surefire-junit47</artifactId>
       <version>2.19.1</version>
    </dependency>
  </dependencies>
</project>

lifecycle.xml -

<?xml version="1.0" encoding="UTF-8"?>
<lifecycles>  
  <lifecycle>  
    <id>customLifeCycle</id>  
    <phases>  
      <phase>  
        <id>compile</id>  
        <executions>  
          <execution>  
            <goals>  
              <goal>mycompile</goal>  
            </goals>  
          </execution>  
        </executions>  
      </phase> 
    </phases>  
  </lifecycle>  
</lifecycles> 

components.xml

 <?xml version="1.0" encoding="UTF-8"?>
<component-set>
  <components>
    <component>
      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
      <role-hint>ear</role-hint>
      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
      <configuration>
        <type>ear</type>
        <extension>ear</extension>
        <language>java</language>
        <packaging>ear</packaging>        
      </configuration>
    </component>

   <component>
      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
      <role-hint>ear</role-hint>
      <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
      <configuration>
        <phases>
          <process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
          <compile>com.test:my-maven-plugin:mycompile</compile>
          <process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
          <test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
          <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
          <install>org.apache.maven.plugins:maven-install-plugin:install</install>
          <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
        </phases>
      </configuration>
    </component>
  </components>
</component-set>

И, переопределенная компиляция mojo -

 @Mojo( name = "mycompile", defaultPhase = LifecyclePhase.COMPILE )
 public class MyCompileMojo extends AbstractMojo{

   @Parameter( defaultValue = "${project}", readonly = true, required = true )
    private MavenProject project;
    public void execute() throws MojoExecutionException, MojoFailureException {
    }
}

Теперь, на этапе компиляции, мне нужен список JAR файлов, которые присутствуют в classpath. Как я могу его получить? Я пробовал следовать - но большинство из них возвращает путь к папке пути и путь к папкам классов

List<String> list1 = project.getCompileClasspathElements();
List<String> list2 = project.getRuntimeClasspathElements();
List<String> list3 = project.getSystemClasspathElements();
List<String> list4 = project.getTestClasspathElements();
List<Dependency> list5 = project.getCompileDependencies();
Properties list6 = project.getProperties();
List<Dependency> list7 = project.getSystemDependencies();
List<Dependency> list8 = project.getRuntimeDependencies();

Моя структура проекта, которая будет скомпилирована

введите описание изображения здесь

Ответ 1

Ключевым компонентом, который вам не хватает, является requiresDependencyResolution, которые представляют собой набор зависимостей, которые будут доступны для плагина. Из ссылка API Mojo:

Отметьте это Mojo как требующее, чтобы зависимости в указанном пути класса были разрешены до его выполнения. [...] Если аннотация отсутствует вообще, mojo не должен делать никаких предположений об артефактах, связанных с проектом Maven.

Чтобы получить доступ к зависимостям времени компиляции проекта, вы можете использовать ResolutionScope.COMPILE:

compile области разрешения = compile + system + provided зависимости

Кроме того, существует также COMPILE_PLUS_RUNTIME, чтобы иметь доступ к зависимым от области выполнения средам, или TEST, чтобы добавить зависимые от тестирования области. Если этот параметр отсутствует для плагина Maven, для него не будут доступны элементы класса пути проекта Maven. Это поведение, с которым вы столкнулись.

Поэтому, если вы хотите, чтобы плагин Maven перехватил список файлов JAR с компиляцией, которые являются зависимостями текущего проекта Maven, вы можете:

@Mojo(name = "mycompile", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.COMPILE)
public class MyCompileMojo extends AbstractMojo {

    @Parameter(defaultValue = "${project}", readonly = true, required = true)
    private MavenProject project;

    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            List<String> list = project.getCompileClasspathElements();
            getLog().info(list.toString());
        } catch (DependencyResolutionRequiredException e) {
            throw new MojoFailureException("Couldn't resolve compile dependencies", e);
        }
    }

}

Метод getCompileClasspathElements() возвращает список путей к файлам JAR для каждой зависимости времени компиляции. Он также будет содержать путь к папке target/classes текущего проекта Maven, поскольку он содержит скомпилированные основные источники Java проекта. Вышеприведенный код просто распечатает этот список. Аналогично, вы должны использовать getTestClasspathElements() вместе с ResolutionScope.TEST, чтобы иметь список зависимостей в тестовых областях, а также зависимости времени компиляции.

Если вам нужен только путь к JAR файлу зависимостей, без классов самого проекта, вы можете использовать метод getArtifacts() вместо:

public void execute() throws MojoExecutionException, MojoFailureException {
    Set<Artifact> artifacts = project.getArtifacts();
    for (Artifact artifact : artifacts) {
        System.out.println(artifact.getFile());
    }
}

Обратите внимание, что для этого необходимо убедиться, что фаза compile (или test-compile) запущена. Списки лениво заполнены. Выполнение mvn clean test гарантирует, что плагин имеет доступ к зависимостям области проверки, если он объявил requiresDependencyResolution of TEST. Точно так же запуск mvn clean compile (наряду с изменением фазы на <phase>compile</phase>) позволит убедиться, что плагин имеет доступ к зависимостям области компиляции, если он объявил requiresDependencyResolution of compile.


Пара примечаний:

  • Файл lifecycle.xml должен находиться внутри src/main/resources/META-INF/maven. Обратите внимание, что этот файл на самом деле полностью не используется в вашей настройке, потому что вы не использовали новый customLifeCycle внутри своего components.xml и вместо этого переопределяете ear;
  • Файл components.xml должен находиться внутри src/main/resources/META-INF/plexus. Обратите внимание, что <compile>com.test:my-maven-plugin:mycompile</compile> должен соответствовать идентификатору группы и значению артефакта плагина;
  • В тестовом проекте должен использоваться такой плагин:

    <packaging>ear</packaging> <!-- because your lifecycle mapping override ear -->
    <dependencies>
      <!-- some dependencies like maven-core -->
      <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-core</artifactId>
        <version>3.0</version>
      </dependency>
    </dependencies>
    <build>
      <plugins>
        <plugin>
          <groupId>com.test</groupId>
          <artifactId>my-maven-plugin</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <extensions>true</extensions>
        </plugin>
      </plugins>
    </build>
    

    Затем вы можете запустить mvn clean package, и плагин корректно распечатает путь к файлам JAR maven-core (например) и его зависимостям.

Ответ 2

Это сработало для меня.

Я нашел его здесь https://www.mkyong.com/java/how-to-print-out-the-current-project-classpath/

package com.mkyong.io;

import java.net.URL;
import java.net.URLClassLoader;

public class App{

    public static void main (String args[]) {

        ClassLoader cl = ClassLoader.getSystemClassLoader();
        URL[] urls = ((URLClassLoader)cl).getURLs();

        for(URL url: urls){
            System.out.println(url.getFile());
        }
    }
}

Ответ 3

По завершении предыдущего ответа вы можете прочитать все такие классы:

public static List<String> getClassPaths() {
    List<String> list = new ArrayList<String>();
    Enumeration res;
    try {
        res = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
        while (res.hasMoreElements()) {
            try {
                URL url = (URL)res.nextElement();
                InputStream is = url.openStream();
                if (is != null) {
                    Manifest manifest = new Manifest(is);
                    Attributes mainAttribs = manifest.getMainAttributes();
                    String classpath = mainAttribs.getValue("Class-Path");
                    if (classpath != null)
                        list.add(classpath);
                }
            }
            catch (Exception e) {
                // Silently ignore wrong manifests or stop the compilation
            }
        }
    } catch (IOException e1) {
    // Silently ignore wrong manifests or stop the compilation
    }
    return list;
}

Если вам нужно углубиться в зависимости:

public static List<String> getClassPaths() {
    List<String> list = new ArrayList<String>();
    Enumeration res;
    try {
        res = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
        while (res.hasMoreElements()) {
            try {
                URL url = (URL)res.nextElement();
                InputStream is = url.openStream();
                if (is != null) {
                    Manifest manifest = new Manifest(is);
                    Attributes mainAttribs = manifest.getMainAttributes();
                    String classpath = mainAttribs.getValue("Class-Path");
                    if (classpath != null)
                        for (String lib : classpath.split(" ")) {
                            try {
                                list.addAll(getClassPathsFromJar(lib));
                            } catch (IOException ioe)
                            {
                                list.add(lib);
                            }
                        }
                }
            }
            catch (Exception e) {
                // Silently ignore wrong manifests or stop the compilation
            }
        }
    } catch (IOException e1) {
    // Silently ignore wrong manifests or stop the compilation
    }
    return list;
}

public static List<String> getClassPathsFromJar(String lib) throws IOException {
    List<String> entries = new ArrayList<String>();
    JarFile jar = new JarFile(lib);
    Manifest manifest = jar.getManifest();
    if (manifest == null) {
        entries.add(lib);
        return entries;
    }
    Attributes mainAttribs = manifest.getMainAttributes();
    String classpath = mainAttribs.getValue("Class-Path");
    if (classpath == null) {
        entries.add(lib);
        return entries;
    }
    for (String l : classpath.split(" ")) {
        entries.addAll(getClassPathsFromJar(l));
    }
    return entries;
}