Reputation: 1494
I've tried many suggestions on StackOverflow, and tested with many combinations of setup and pom.xml for 3 days, none of them works. Please help.
I started with a big project with a lot of dependencies, spring-boot, hibernate, etc. Then I create another small console project which import and use some classes from the big project. They are not parent and child project. All I do is add <dependency/>
to the child project pom, like this.
P.S. the big project has a <parent/>
spring-boot-starter-parent and use spring-boot-maven-plugin.
<dependency>
<groupId>myGroup</groupId>
<artifactId>bigProject</artifactId>
<version>1.0.1</version>
</dependency>
This works on Eclipse with m2e, I just use "Run as" java application and the small project works. But I need to upload and run those project on my linux VM, which does not use GUI and Eclipse, only terminal.
Then after some reading, I try to use maven exec plugin to run the small project. My steps:
1. do mvn clean install
on the big project, confirmed that it appears in my /.m2, local repository.
2. run mvn compile
on small project
3. run mvn exec:java
on small project
It fails on step 2, those import ...
in the class of small project throw package xxx does not exist. maven fail with compilation error.
Then, I try to simplify the problem. I create two test projects with only 1 class, myLib and HelloWorld console application, then I add myLib dependency (pom). HelloWorld project to print a message from the class in myLib package. run step 1 to 3. It works.
public class App
{
public static void main( String[] args )
{
//SystemLog from big project, does not work
//SystemLog log = new SystemLog();
//log.setValue("test value");
//System.out.println(log.getValue());
//CustomMessage from myLib, works fine
CustomMessage cm = new CustomMessage();
cm.setTheMessage("custom message");
System.out.println(cm.getTheMessage() );
System.out.println(CustomMessage.defaultMsg);
}
}
pom.xml of small project
<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>test</groupId>
<artifactId>dependOnOthers</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dependOnOthers</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>myLibrary</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com</groupId>
<artifactId>bigproject</artifactId>
<version>1.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<includePluginDependencies>true</includePluginDependencies>
<mainClass>test.dependOnOthers.App</mainClass>
<!-- <arguments> <argument>argument1</argument> </arguments> -->
<!-- <arguments> <argument>-classpath</argument> <argument>target/lib/bigproject-1.0.1.jar</argument>
</arguments> -->
</configuration>
</plugin>
</plugins>
</build>
</project>
Then I add a reference to big project, try to print a log message using HelloWorld, it pass step 2, mvn compile, but when I do step 3, mvn exec:java, java.lang.ClassLoader.loadClass()
throw ClassNotFoundException on the line where I new an SystemLog() instance, the class defined in big project.
Summarize: Goal: try to run a console application using Maven exec plugin, which has a dependency on another project, that is installed in local repo /.m2 The SystemLog class is a model class with hibernate annotations. 1. small project depend on big project, fail on mvn compile, package does not exist. 2. HelloWorld depend on myLib, works fine. 3. HelloWorld depend on big project, fail at runtime with ClassNotFoundException.
Upvotes: 0
Views: 722
Reputation: 1287
It's a little late but i ran in the same error, migrating a project from 1.5.3 to 2.1.4
I have found a solution for this problem.
Spring Boot has changed the jar structure in version 2.0.0+, so you don't need to specify your class as <mainClass>test.dependOnOthers.App</mainClass>
, you need to point JarLauncher as main entry point.
When the plugin will execute the jar, java will call the main method JarLauncher and several code of spring will be called after that he reads the manifest and call the class definied in Start-Class:
. in your case test.dependOnOthers.App.
<configuration>
<!-- Since version 2 of spring, the jar is packed in
another way and has his main method here, don't worry in the MANIFEST file is described which file to boot -->
<mainClass>org.springframework.boot.loader.JarLauncher</mainClass>
The old strucutre of Spring 1.0, was the classical java way todo it, so the java classloader can load it without problems and refer to the class when it is in the classpath, with the version 2.0.0+, they copy user class files and dependency into BOOT-INF, so the java classloader cannot load it anymore, you need to use the Spring classloader to get the class instance.
Upvotes: 1
Reputation: 1494
I have a workaround and know what is causing the problem, but don't know all the details, hope that someone will comment on this, or elaborate the answer.
The thing that cause this problem is spring-boot-maven-plugin
, which I use to run spring-boot embedded tomcat server, using mvn spring-boot:run
. This plugin seems to change something on the .jar file, maybe the manifest?
The workaround is to remove this plugin, run mvn clean install
, that .jar installed in local repository will work correctly. run mvn compile
on the small project. Then add the plugin back to big project, run mvn spring-boot:run
I do not know what the plugin changes that result in a .jar with package not exist, does it changes package name?
My workaround is clumsy, if there is a way to choose to compile with or without spring-boot-maven-plugin
by defining maven goal, so that I do not need to change the pom for different build (with/without plugin). That would be a better solution.
Upvotes: 0