Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does maven decide when to use the target folder for classpath

I have a question regarding how maven calculates the classpath during building. Specifically, what controls when the "target/classes" is used and when the "jar" from a repository (local/remote) is used.

I have a project on version 1.0.0-SNAPSHOT where the artifacts have NOT been installed/deployed so there is no "jar" in some repository (remote or local) to resolve them. I want to run "generate-sources" WITHOUT installing locally (no 'mvn install' run).

The structure looks like this:

parent-prj
parent-prj/sub-prj
parent-prj/gen-src-prj <--- This depends on 'sub-prj'

When I run "mvn -am -pl parent-prj/gen-src-prj generate-sources" in order to just generate some java files, it does not work:

[ERROR] Failed to execute goal on project gen-src-prj: Could
 not resolve dependencies for project 
mygrp:gen-src-prj:jar:1.0.0-SNAPSHOT: 
Could not find artifact 
mygrp:sub-prj:jar:1.0.0-SNAPSHOT -> [Help 1]

Using debug output and adding "dependency:build-classpath" I can confirm that maven ignores the presence of "sub-prj" in the reactor and looks for a "jar" somewhere which it can't find. Yet the project is printed in the reactor summary:

[INFO] Reactor Summary:
[INFO] 
[INFO] parent-prj ..................................... SUCCESS [  0.625 s]
[INFO] sub-prj ........................................ SUCCESS [  0.018 s]
[INFO] gen-src-prj .................................... FAILURE [  0.040 s]

The interesting thing I noticed is that running the compile goal works fine! This uses sub-prj/target/classes (as shown by dependency:build-classpath) and has no trouble generating the sources and even compiling them: "mvn -am -pl parent-prj/gen-src-prj compile"

So here are the points I want to understand:

  1. Why does the compile goal work but the generate-sources doesn't work?
  2. At what point does maven decide to use the output folder of previous projects on the reactor classpath instead of looking for a jar?
  3. Is there a way for generate-sources to run directly as I want it EVEN WITHOUT having its dependencies resolved?

Regarding (3) my generation tool is a utility invoked by:

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <executions>
            <execution>
                <phase>generate-sources</phase>
                <goals>
                    <goal>java</goal>
                </goals>
            </execution>
        </executions>

The tool reads some XML in src/main/resources and generates Java files and does NOT need anything in its class-path (so there is no need for maven to resolve it).

Also note that I would be interested to understand (1) and (2) even if a solution for (3) is provided.


EDIT: Per comment request, adding full example

parent-prj/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>mygrp</groupId>
    <artifactId>parent-prj</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <packaging>pom</packaging>

    <modules>
        <module>sub-prj</module>
    <module>gen-src-prj</module>
    </modules>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.3</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.9</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

parent-prj/sub-prj/pom.xml

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
    xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>mygrp</groupId>
        <artifactId>parent-prj</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>sub-prj</artifactId>
</project>

parent-prj/gen-src-prj/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>

    <parent>
        <groupId>mygrp</groupId>
        <artifactId>parent-prj</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>gen-src-prj</artifactId>

    <dependencies>
        <dependency>
            <groupId>mygrp</groupId>
            <artifactId>sub-prj</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <includeProjectDependencies>false</includeProjectDependencies>
                    <includePluginDependencies>true</includePluginDependencies>
                    <mainClass>uk.co.real_logic.sbe.SbeTool</mainClass>
                    <systemProperties>
                        <systemProperty>
                            <key>sbe.output.dir</key>
                            <value>${project.build.directory}/generated-sources/java</value>
                        </systemProperty>
                        <systemProperty>
                            <key>sbe.validation.warnings.fatal</key>
                            <value>true</value>
                        </systemProperty>
                    </systemProperties>
                    <arguments>
                        <argument>${project.build.resources[0].directory}/Examples.xml</argument>
                    </arguments>
                    <workingDirectory>${project.build.directory}/generated-sources/java</workingDirectory>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>uk.co.real-logic</groupId>
                        <artifactId>sbe-tool</artifactId>
                        <version>1.7.10</version>
                    </dependency>
                </dependencies>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>target/generated-sources/java/</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

EDIT: Armed with the knowledge from the answers I have come up with this workaround that allows one to achieve the desired behaviour. I list the dependencies in a profile that is active by default, then use another profile to run generate-sources with no dependencies active, like follows:

parent-prj/gen-src-prj/pom.xml

<profiles>
    <profile>
        <id>default</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <dependencies>
            <dependency>
                <groupId>mygrp</groupId>
                <artifactId>sub-prj</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </profile>

    <profile>
        <id>excludeDependency</id>
        <dependencies>
        </dependencies>
    </profile>
</profiles>

To generate sources with above, use: mvn -PexcludeDependency generate-sources

like image 925
Alexandros Avatar asked May 11 '18 08:05

Alexandros


2 Answers

Maven can reference only output generated in current Session (during currently executing shell command). It uses the most "mature" place to look for the "output":

  • If compile is run - the classes end up in the target/classes dir, thus other modules can reference that
  • If package is run - then target/*.jar is created and this jar file ends up in the classpath instead
  • If install is run - then jar file ends up in the local repository - which is what ends up on the classpath

So there are 3 factors that impede your task:

  • maven-exec-plugin requires dependency resolution (as pointed out by @mondaka)
  • Your module1 references module2
  • generate-sources is run before the compilation. Thus module2 is not yet prepared to be used as a dependency.

So if you want to do it your way - you'll have to run at least compile phase each time you use anything from the Default Lifecycle. Or you could write your own plugin that doesn't require dependency resolution.

like image 96
Stanislav Bashkyrtsev Avatar answered Oct 31 '22 19:10

Stanislav Bashkyrtsev


This problem is related to an open maven bug:

https://issues.apache.org/jira/browse/MNG-3283

The issue says: "The problem only occurs when a plugin binds itself to the generate-sources phase and has @requiresDependencyResolution".

I have checked that exec-maven-plugin Mojo have indeed requiresDependencyResolution = ResolutionScope.TEST. You can see that on https://github.com/mojohaus/exec-maven-plugin/blob/master/src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java

Then, your only option is to use compile or process-classes phases. This is a Major open bug from 2007...

like image 42
mondaka Avatar answered Oct 31 '22 20:10

mondaka