Nar dependency in multi-module maven project - maven

I set up a multi module maven project, which is comprised of a module destined to build nar jni library, and a jar packaged module that is dependent on that library.
I am able to install the nar library to my local maven repository, but I fail to use it in dependent module.
For instance, I run mvn nar:nar-unpack and I get:
[INFO] ------------------------------------------------------------------------
[INFO] Building nar-dependent 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- nar-maven-plugin:3.2.0:nar-unpack (default-cli) # nar-dependent ---
[INFO] Unpacking 0 dependencies to /home/przemek/Documents/stimulant/nar-dependent/target/nar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
It seems that there are no nar dependencies, which is obviously not true.
Moreover, trying to execute the main method of the class that makes use of the jni library fails:
mvn exec:java -Dexec.mainClass=App
[INFO] --- exec-maven-plugin:1.4.0:java (default-cli) # nar-dependent ---
[WARNING]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.UnsatisfiedLinkError: no nar-library-1.0-SNAPSHOT in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1865)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at jnibook.NarSystem.loadLibrary(NarSystem.java:23)
at jnibook.HelloWorld.<clinit>(HelloWorld.java:10)
at App.main(App.java:9)
... 6 more
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
The structure of the project looks like this:
.
├── nar-dependent
│   ├── pom.xml
│   └── src
│   └── main
│   └── java
│   └── App.java
├── nar-library
│   ├── pom.xml
│   └── src
│   ├── main
│   │   ├── c
│   │   │   └── HelloWorld.c
│   │   ├── include
│   │   ├── java
│   │   │   └── jnibook
│   │   │   └── HelloWorld.java
│   │   └── resources
│   └── test
│   └── java
├── parent
│   └── pom.xml
Here is the parent pom.xml:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sidec</groupId>
<artifactId>stimulant</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>../nar-library</module>
<module>../nar-dependent</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
The nar-library module pom.xml:
<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>sidec</groupId>
<artifactId>stimulant</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<artifactId>nar-library</artifactId>
<packaging>nar</packaging>
<name>nar-library</name>
<properties>
<skipTests>true</skipTests>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.github.maven-nar</groupId>
<artifactId>nar-maven-plugin</artifactId>
<version>3.2.0</version>
<extensions>true</extensions>
<configuration>
<cpp>
<exceptions>false</exceptions>
</cpp>
<libraries>
<library>
<type>jni</type>
<linkCPP>false</linkCPP>
<narSystemPackage>jnibook</narSystemPackage>
</library>
</libraries>
<javah>
<includes>
<include></include>
</includes>
</javah>
</configuration>
</plugin>
</plugins>
</build>
</project>
The nar-dependent pom.xml
<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>sidec</groupId>
<artifactId>stimulant</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<artifactId>nar-dependent</artifactId>
<packaging>jar</packaging>
<name>nar-dependent</name>
<build>
<plugins>
<plugin>
<groupId>com.github.maven-nar</groupId>
<artifactId>nar-maven-plugin</artifactId>
<version>3.2.0</version>
<extensions>true</extensions>
<!--<executions>-->
<!--<execution>-->
<!--<id>nar-download</id>-->
<!--<goals>-->
<!--<goal>nar-download</goal>-->
<!--</goals>-->
<!--</execution>-->
<!--</executions>-->
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>sidec</groupId>
<artifactId>nar-library</artifactId>
<version>1.0-SNAPSHOT</version>
<type>nar</type>
</dependency>
</dependencies>
</project>
Finally, as a proof that it is really the HelloWorld project, a library class:
package jnibook;
public class HelloWorld {
public native void print();
static {
NarSystem.loadLibrary();
}
}
and a client app:
import jnibook.HelloWorld;
public class App {
public static void main(String ... args){
(new HelloWorld()).print();
}
}
I referenced https://maven-nar.github.io/examples.html with no success.
I have no idea what is going wrong.
Any ideas? Here is zip with project.

This might be an outdated question, but I'll answer all the same :
When running the java JNI app, it must be told where to find the .so library holding the relevant native C code used by JNI.
For example, if you closed your app in the executable jar app.jar :
java -Djava.library.path=[path to the .so native C library] -jar app.jar
PS - you can see that the JVM can't find the native C library thanks to the exception : java.lang.UnsatisfiedLinkError: no nar-library-1.0-SNAPSHOT in java.library.path

I have tried my own variant of your example with version 3.6.0 of the plugin. With that version, I at least get
Unpacking 1 dependencies to /home/karsten/svn/hellotest/target/nar
and the .so gets unpacked when I run mvn nar:nar-unpack in the dependent module.
But the only way I have found to make mvn nar:nar-integration-test work in the dependent module, is by writing
LD_LIBRARY_PATH=target/nar/hellojni-0.0-amd64-Linux-gpp-jni/lib/amd64-Linux-gpp/jni mvn nar:nar-integration-test
I tried several ways of specifying java.library.path, but with no success.

Related

Missing plugin and feature folders for an update site built with Maven Tycho

I am building an eclipse plugin with Tycho. I want to create an Update Site for it. I have the following components:
parent (pom)
the plugin (eclipse-plugin)
the feature (eclipse-feature)
the update site (eclipse-repository)
But when I run mvn clean package in the target folder of my update site project I have:
├── lorem-ipsum-eclipse-update-1.0.1-SNAPSHOT.zip
├── local-artifacts.properties
├── p2agent
│   ├── org.eclipse.equinox.p2.core
│   │   └── cache
│   │   └── artifacts.xml
│   └── org.eclipse.equinox.p2.engine
│   └── profileRegistry
├── p2artifacts.xml
├── p2content.xml
├── repository
│   ├── artifacts.jar
│   ├── artifacts.xml.xz
│   ├── content.jar
│   ├── content.xml.xz
│   └── p2.index
└── targetPlatformRepository
└── content.xml
As you can see the plugin and feature folders are missing in target/repository.
This is my parent pom:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.lorem.ipsum.eclipse</groupId>
<version>1.0.1-SNAPSHOT</version>
<artifactId>lorem-ipsum-eclipse-parent</artifactId>
<packaging>pom</packaging>
<properties>
<tycho-version>2.2.0</tycho-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>lorem-ipsum-eclipse-feature</module> <!-- packaging: eclipse-feature -->
<module>lorem-ipsum-eclipse-plugin</module> <!-- packaging: eclipse-plugin -->
<module>lorem-ipsum-eclipse-update</module> <!-- packaging: eclipse-repository -->
</modules>
<repositories>
<repository>
<id>2020-12</id>
<layout>p2</layout>
<url>http://download.eclipse.org/releases/2020-12</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho-version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-p2-repository-plugin</artifactId>
<version>${tycho-version}</version>
<configuration>
<includeAllDependencies>true</includeAllDependencies>
<createArtifactRepository>true</createArtifactRepository>
<compress>true</compress>
</configuration>
</plugin>
<!--Enable the replacement of the SNAPSHOT version in the final product configuration-->
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-packaging-plugin</artifactId>
<version>${tycho-version}</version>
<executions>
<execution>
<phase>package</phase>
<id>package-feature</id>
<configuration>
<finalName>${project.artifactId}_${unqualifiedVersion}.${buildQualifier}</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
What am I doing wrong?
Thanks in advance.
UPDATE: As howlger requested here is update site's category.xml.
<?xml version="1.0" encoding="UTF-8"?>
<site>
<feature id="com.lorem.ipsum.eclipse.feature" version="0.0.0">
<category name="com.lorem.ipsum.eclipse.category"/>
</feature>
<category-def name="com.lorem.ipsum.eclipse.category" label="Lorem Ipsum">
<description>
Contains features for Lorem Ipsum plugin
</description>
</category-def>
</site>
By the way my file is named site.xml because if I named category.xml I have this error when i tried to run any maven goal:
$ mvn clean
...
[ERROR] Cannot resolve project dependencies:
[ERROR] Software being installed: lorem-ipsum-eclipse-update raw:1.0.1.'SNAPSHOT'/format(n[.n=0;[.n=0;[-S]]]):1.0.1-SNAPSHOT
[ERROR] Missing requirement: lorem-ipsum-eclipse-update raw:1.0.1.'SNAPSHOT'/format(n[.n=0;[.n=0;[-S]]]):1.0.1-SNAPSHOT requires 'org.eclipse.equinox.p2.iu; com.lorem.ipsum.eclipse.feature.feature.group 0.0.0' but it could not be found
[ERROR]
[ERROR] See https://wiki.eclipse.org/Tycho/Dependency_Resolution_Troubleshooting for help.
[ERROR] Cannot resolve dependencies of MavenProject: com.globant.augmented.coding.eclipse:lorem-ipsum-eclipse-update:1.0.1-SNAPSHOT # /home/me/workspaces/java/lorem-ipsum-eclipse-project/lorem-ipsum-eclipse-update/pom.xml: See log for details -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MavenExecutionException
I followed the instructions of the book Eclipse 4 Plug-in Development by Example Beginners Guide by Dr Alex Blewitt which uses an old version of tycho (0.18.0) and I have used 2.2.0. Maybe in this version they fixed the fact of renaming site to category since in the same book they mentioned that it was a meaningless change.
I quote:
Rename the site.xml file to category.xml . (This is an entirely
pointless change required by p2 since the files are identical in
format.)
According the the error message (... lorem-ipsum-eclipse-update ... Missing requirement: ... com.lorem.ipsum.eclipse.feature.feature.group ...) the update site category.xml refers a missing feature.
Make sure to use the same feature ID (<feature id="...") in the following two files:
<your-feature>/feature.xml
<your-update-site>/category.xml
See also the vogella tutorial Eclipse Tycho for building Eclipse Plug-ins and RCP applications: in category.xml the feature is referenced via the ID com.vogella.tycho.feature.
com.vogella.tycho.feature

docker multistage spring boot build pom + inner dependencies

I am trying to make a spring boot multistage build, I have a spring boot project X that contains two util projects as dependencies in other folder, when I try to make the build it fails because this dependencies does not exist.
I tried using multi module maven project but this utils will be used in other projects.
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 08:23 min
[INFO] Finished at: 2019-09-27T01:29:09Z
[INFO] Final Memory: 44M/228M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project projectX: Could not resolve dependencies for project com.demo:projectX:jar:0.1: The following artifacts could not be resolved: com.util:util1:jar:0.1, com.util:util2:jar:0.1: Could not find artifact com.util:util1:jar:0.1 in spring-milestones (https://repo.spring.io/milestone) -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException
ERROR: Service 'projectX' failed to build: The command '/bin/sh -c ./mvnw dependency:go-offline -B' returned a non-zero code: 1
(edit) Here is dockerfile for multistage maven build
(edit) the docker build command and context path is from parent folder
FROM openjdk:8-jdk-alpine as build-util1
WORKDIR /util1
COPY ./components/util1/mvnw .
COPY ./components/util1/.mvn .mvn
COPY ./components/util1/pom.xml .
COPY ./components/util1/src src
RUN ./mvnw clean install
FROM openjdk:8-jdk-alpine as build-util2
WORKDIR /util
COPY --from=build-util1 /root/.m2 /root/.m2
COPY ./components/util2/mvnw .
COPY ./components/util2/.mvn .mvn
COPY ./components/util2/pom.xml .
COPY ./components/util2/src src
RUN ./mvnw clean install
FROM openjdk:8-jdk-alpine as build
WORKDIR /app
COPY --from=build-util2 /root/.m2 /root/.m2
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
RUN ./mvnw dependency:go-offline -B
COPY src src
RUN ./mvnw -X package -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
FROM openjdk:8-jre-alpine
ARG DEPENDENCY=/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.demo.projectx.ProjectX"]
Here is the pom.xml for the project X
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>projectX</artifactId>
<version>0.1</version>
<name>projectX</name>
<description>projectX</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
<docker.image.prefix>jxssw</docker.image.prefix>
<docker.image.name>${project.artifactId}</docker.image.name>
<docker.image.tag>${project.version}</docker.image.tag>
</properties>
<dependencies>
<!-- utils -->
<dependency>
<groupId>com.util</groupId>
<artifactId>util1</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>com.util</groupId>
<artifactId>util2</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Dockerfile Maven -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.10</version>
<configuration>
<googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
<repository>${docker.image.prefix}/${docker.image.name}</repository>
<tag>${project.version}</tag>
</configuration>
<executions>
<execution>
<id>build</id>
<phase>clean</phase>
<goals>
<goal>build</goal>
<goal>tag</goal>
</goals>
</execution>
<execution>
<id>push</id>
<phase>deploy</phase>
<goals>
<goal>push</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Dockerfile Maven -->
</plugins>
<finalName> ${project.artifactId}</finalName>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
(edit) add the folder structure:
.(parent)
├── projects
| └── projectX
│ ├── pom.xml
│ ├── Dockerfile
│ └── src
│ └── main
├── components
| └── util1
│ ├── pom.xml
│ └── src
│ └── main
| └── util2
│ ├── pom.xml
│ └── src
│ └── main

Spring boot test multi module maven application

I have a multi-module maven application which uses Spring boot:
- spring boot parent
- myproject parent (both parent and module pom)
- module1
- module2
- module-it (integration tests)
In my module-it, I add the other modules as dependencies.
When I build my project with maven, I get "Build Success":
mvn clean install
So far so good.
Yet I would like each of my modules to be an executable jar at the end of the build. With the above settings, the manifest is not defined and the jar is not executable.
To fix this issue, I've added the following in my module1 and module2 pom files:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
With this setting, my jar file is executable but I cannot build anymore. Classes that I use in my module-it are not found.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project module-it: Compilation failure: Compilation failure:
[ERROR] /home/user/<path-to-project>/testing/module-it/src/test/java/com/mycompany/testing/greeting/GreetingControllerIT.java:[20,17] cannot find symbol
[ERROR] symbol: class GreetingController
[ERROR] location: class com.mycompany.testing.greeting.GreetingControllerIT
[ERROR] /home/user/<path-to-project>/testing/module-it/src/test/java/com/mycompany/testing/hello/HelloControllerIT.java:[20,17] cannot find symbol
[ERROR] symbol: class HelloController
[ERROR] location: class com.mycompany.testing.hello.HelloControllerIT
[ERROR] /home/user/<path-to-project>/testing/module-it/src/test/java/com/mycompany/testing/greeting/GreetingControllerIT.java:[16,27] cannot find symbol
[ERROR] symbol: class GreetingController
[ERROR] /home/user/<path-to-project>/testing/module-it/src/test/java/com/mycompany/testing/hello/HelloControllerIT.java:[16,27] cannot find symbol
[ERROR] symbol: class HelloController
Can you please help me understand why spring-boot-maven-plugin makes my build fail and how I can solve the issue?
Thanks in advance for your help.
To solve this issue, we can add a classifier as described in the documentation custom repackage classifier
The plugin then becomes:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
Also you could set repackage goal parameter attach to false:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
At least for the spring-boot-starter-parent:2.6.0 pom the configuration for the spring-boot-maven-plugin contains an <id>repackage</id> for the execution of the repackage goal
So I had to add the line <id>repackage</id> too.
Full configuration:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
Late answer to an old question but i've just been working on this for the past hours. Even though the previous answers were helpfull they don't explain why this problem is happening.
For others that may comes accross this issue here is a detailed explnation why it's not working
In a Nutshell
Usualy Maven package your application as a regular .jar with all compiled class being in a well known location in the .jar file.
So it's pretty straighforward for a compiler to import the .jar as a library and to load the available .class.
But the spring-boot-maven-plugin is actually modifying the .jar structure to leverage spring-boot logic when you start the .jar application.
In short, the .class are not available to be imported as a "library" from the resulting .jar, because the spring class have took the well known location for itself.
Detailed explanation
Let's explore the problem with an example
Project structure
Let's imagine a project with multiple maven modules like so
my-app/ -- The parent project
├─ pom.xml
├─ application/
│ ├─ pom.xml
├─ integration-tests/
│ ├─ pom.xml
Given the following pom.xml files:
my-app/pom.xml:
<project [...]>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/>
</parent>
<groupId>com.me</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>application</module>
<module>integration-tests</module>
</modules>
</project>
my-app/application/pom.xml:
<project [...]>
<parent>
<groupId>com.me</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>application</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
my-app/integration-tests/pom.xml:
<project [...]>
<parent>
<groupId>com.me</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>integration-tests</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.me</groupId>
<artifactId>application</artifactId>
</dependency>
</dependencies>
</project>
Why is it not building
Let's try to package our app
/my-app$ mvn package
Of course it will miserably fail with an error cannot find symbol, but why is it so?
Let's take a look at our architecture after the failed build:
my-app/ -- The parent project
├─ pom.xml
├─ application/
│ ├─ pom.xml
│ ├─ target/
│ │ ├─ application-1.0.0-SNAPSHOT.jar
│ │ ├─ application-1.0.0-SNAPSHOT.jar.original
├─ integration-tests/
│ ├─ pom.xml
│ ├─ target/
The spring-boot-maven-plugin has done several things to the application module output:
renamed the compiled application-1.0.0-SNAPSHOT.jar to application-1.0.0-SNAPSHOT.jar.original
created it's own .jar with the name of application-1.0.0-SNAPSHOT.jar
Let's explore the structure of the application-1.0.0-SNAPSHOT.jar:
BOOT-INF/
├─ classes/
│ ├─ com/
│ │ ├─ me/ -- The compiled .class of your project reside here
META-INF/
org/
├─ springframework/
│ ├─ boot/ -- contains the spring boot loader classes
As you can see the .class files at the root of your .jar are the spring boot loader classes, not our own .class that are relegated to the BOOT-INF/classes/ folder.
This is not conventional, and when the .jar is imported as a dependency it won't search here for class to import.
Because of that, when maven try to package the integration-tests module, it fails because the class present in the application-1.0.0-SNAPSHOT.jar are actually a bunch of spring class instead of the one you are trying to import from application module.
If you were to look at the structure of the application-1.0.0-SNAPSHOT.jar.origial it would be something like so:
META-INF/
com/
├─ me/ -- contains the spring boot loader classes
Solution
Getting rid of spring-boot-maven-plugin is not an acceptable solution; Of course your project will be buildable, but the resulting .jar won't be a spring boot standalone running .jar.
Instead you can instruct the spring-boot-maven-plugin to not replace the original jar and to build to spring boot jar with another name.
To do so you'll need to configure the spring-boot-maven-plugin in the application module:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Now when you build your project you'll have something like that:
my-app/ -- The parent project
├─ pom.xml
├─ application/
│ ├─ pom.xml
│ ├─ target/
│ │ ├─ application-1.0.0-SNAPSHOT.jar -- the original untouched .jar
│ │ ├─ application-1.0.0-SNAPSHOT-exec.jar -- the spring boot executable .jar
├─ integration-tests/
│ ├─ pom.xml
│ ├─ target/
│ │ ├─ integration-tests-1.0.0-SNAPSHOT.jar

Maven creates class files in wrong directory

I just started learning Maven. I have two java files and they are shown below
I compiled it successfully using 'mvn compile' and able to see the class files
However, I expect 'target/classes/src2/SecProg.class' instead of 'target/classes/SecProg.class'
Output
./target/classes/SecProg.class
./target/classes/src1/FirstProg.class
Please let me know what am I doing wrong
My source tree looks like below
[sathish#oc3855733574 java_tools]$ tree
.
├── pom.xml
├── pom.xml_org
├── src1
│   └── FirstProg.java
├── src2
│   └── SecProg.java
My POM.xml looks like below
<project 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>java_tools</groupId>
<artifactId>first_prog</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<build>
<sourceDirectory>.</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<includes>
<include>src2/*.java</include>
<include>src1/*.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>

How to structure a multi-modules Maven project to compile it at once?

I have a Maven project with multiple modules and sub-modules and i want to compile it at once, i.e. using only one call to "mvn clean install".
For a basic project, the following structure would work:
.
├── modules
│   ├── moduleA
│   │   └── pom.xml <--- Module A POM
│   ├── moduleB
│   │   └── pom.xml <--- Module B POM
│   └── pom.xml <--- Super POM (at the root of "modules" folder)
└── pom.xml <--- Aggregator POM
With the aggregator being:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>aggregator</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>modules</module>
<module>modules/moduleA</module>
<module>modules/moduleB</module>
</modules>
</project>
The Super 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>super-pom</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Module A's 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>moduleA</artifactId>
<parent>
<groupId>org.test</groupId>
<artifactId>super-pom</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
</project>
Module B is similar.
When at the root of the project, running "mvn clean install" command gives (after cleaning up the .m2/repository folder):
[...]
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] super-pom .......................................... SUCCESS [ 0.450 s]
[INFO] moduleA ............................................ SUCCESS [ 1.746 s]
[INFO] moduleB ............................................ SUCCESS [ 0.029 s]
[INFO] agregator .......................................... SUCCESS [ 0.006 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
Now if I want something that is more complex (but still using one super POM), such as:
.
├── modules
│   ├── lib1
│   │   ├── moduleA1
│   │   │   └── pom.xml
│   │   ├── moduleB1
│   │   │   └── pom.xml
│   │   └── pom.xml <--- lib1 aggregator POM
│   ├── lib2
│   │   ├── moduleA2
│   │   │   └── pom.xml
│   │   ├── moduleB2
│   │   │   └── pom.xml
│   │   └── pom.xml <--- lib2 aggregator POM
│   └── pom.xml <--- Super POM
└── pom.xml <--- Aggregator POM
With the root POM being:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>agregator</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>modules</module>
<module>modules/lib1</module>
<module>modules/lib2</module>
</modules>
</project>
Lib1 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>lib1-agregator</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>moduleA1</module>
<module>moduleB1</module>
</modules>
</project>
And, for instance moduleA1 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>moduleA1</artifactId>
<parent>
<groupId>org.test</groupId>
<artifactId>super-pom</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
</project>
Maven does not manage to resolve the POM files (after cleaning up the .m2/repository folder):
[INFO] Scanning for projects...
[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[WARNING] 'parent.relativePath' of POM org.test:moduleA1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleA1/pom.xml) points at org.test:lib1-agregator instead of org.test:super-pom, please verify your project structure # line 7, column 13
[FATAL] Non-resolvable parent POM for org.test:moduleA1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13
[WARNING] 'parent.relativePath' of POM org.test:moduleB1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleB1/pom.xml) points at org.test:lib1-agregator instead of org.test:super-pom, please verify your project structure # line 7, column 13
[FATAL] Non-resolvable parent POM for org.test:moduleB1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13
[WARNING] 'parent.relativePath' of POM org.test:moduleA2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleA2/pom.xml) points at org.test:lib2-agregator instead of org.test:super-pom, please verify your project structure # line 7, column 13
[FATAL] Non-resolvable parent POM for org.test:moduleA2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13
[WARNING] 'parent.relativePath' of POM org.test:moduleB2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleB2/pom.xml) points at org.test:lib2-agregator instead of org.test:super-pom, please verify your project structure # line 7, column 13
[FATAL] Non-resolvable parent POM for org.test:moduleB2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13
#
[ERROR] The build could not read 4 projects -> [Help 1]
[ERROR]
[ERROR] The project org.test:moduleA1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleA1/pom.xml) has 1 error
[ERROR] Non-resolvable parent POM for org.test:moduleA1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13 -> [Help 2]
[ERROR]
[ERROR] The project org.test:moduleB1:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib1/moduleB1/pom.xml) has 1 error
[ERROR] Non-resolvable parent POM for org.test:moduleB1:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13 -> [Help 2]
[ERROR]
[ERROR] The project org.test:moduleA2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleA2/pom.xml) has 1 error
[ERROR] Non-resolvable parent POM for org.test:moduleA2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13 -> [Help 2]
[ERROR]
[ERROR] The project org.test:moduleB2:[unknown-version] (/Users/ben/IdeaProjects/ComplexMavenStructure/modules/lib2/moduleB2/pom.xml) has 1 error
[ERROR] Non-resolvable parent POM for org.test:moduleB2:[unknown-version]: Could not find artifact org.test:super-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 7, column 13 -> [Help 2]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException
[ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/UnresolvableModelException
I need to first build the super pom:
cd modules/
mvn clean install
And only then will it compile:
[INFO] Reactor Summary:
[INFO]
[INFO] super-pom .......................................... SUCCESS [ 0.271 s]
[INFO] moduleA1 ........................................... SUCCESS [ 1.202 s]
[INFO] moduleB1 ........................................... SUCCESS [ 0.027 s]
[INFO] lib1-agregator ..................................... SUCCESS [ 0.006 s]
[INFO] moduleA2 ........................................... SUCCESS [ 0.027 s]
[INFO] moduleB2 ........................................... SUCCESS [ 0.022 s]
[INFO] lib2-agregator ..................................... SUCCESS [ 0.007 s]
[INFO] agregator .......................................... SUCCESS [ 0.007 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
How would you structure the project to make it work without this two-steps compilation?
[EDIT]: as discussed in the comments, adding the relativePath of the Super POM to the modules POMs would make the code compile with one command line.
However, if I want to distribute only lib1 to some developers, even though my super POM is on a Maven repository, lib1 would not compile without the whole project structure. This makes the project less modular.
Let me start like you did, but I name the things a little bit differently:
.
├── modules-root
│ ├── moduleA
│ │ └── pom.xml <--- Module A POM
│ ├── moduleB
│ │ └── pom.xml <--- Module B POM
│ └── pom.xml <--- modules root
└── pom.xml <--- project-root
Let's start with the project-root, which will look like this:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>project-root</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>modules-root</module>
</modules>
</project>
The module-parent will look like this. I will emphasis that this contains only the reference to the moduleA and moduleB and will inherit from the project-root:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.test</groupId>
<artifactId>project-root</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>org.test.module</groupId>
<artifactId>module-parent</artifactId>
<packaging>pom</packaging>
<modules>
<module>moduleA</module>
<module>moduleB</module>
</modules>
</project>
moduleA will look like this. Pay attention that this will inherit from module-parent (parent) which is exactly one level above...
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.test.module</groupId>
<artifactId>module-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>moduleA</artifactId>
<packaging>..</packaging>
<....other dependencies..>
</project>
If you use this kind of structure you can simply go to the project-root level and do:
mvn clean install
Furthermore afterwards you can use things like this:
mvn -pl moduleA ...
...to build only moduleA (but stay at the project-root level...).
module-parent might look like wasted or superfluous in this example, but if you get more modules you could define their supplemental dependencies via dependencyManagement or may changing plugin configurations via pluginManagement which will only be used in this sub area (moduleA, moduleB, ...). If your project becomes larger, you will get more module-parents in parallel..which contain different parts of your applications...and different intentions which can be achieved with this structure.
One more thing is to mention; I have changed the groupId from org.test to org.test.module in the module-parent. This is sometimes useful if you have a large number of modules cause the groupId represents the folder structure in your repository (as java packages do in a Java project)... this give you an better overview...
The project-root is the location to define the overall usable dependencies via dependencyManagement etc....and the used plugins which should be defined via pluginManagement... or may be using maven-enforcer-plugin to define overall project rules...
Typical scenarios for this kind of structure are Java EE projects or other large projects (may be with 300...or 1000 modules yes they exist)...
If you get more modules you can use the multi-thread capability of maven and build your project with:
mvn -T 4 clean install
from the project-root which reduces the build time dramatically.

Resources