Solving the problem of missing Jar package when Maven relies on system-level deployment scope

Question

When developing the springboot project, maven introduced the local third-party jar package and it ran normally in the idea. After deploying it into a jar, it reports that the class cannot be found.
The error is as follows:

ERROR SpringApplication.reportFailure(834) | Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'persistenceExceptionTranslationPostProcessor' defined in class path resource [org/springframework/boot/autoconfigure/dao/PersistenceExceptionTranslationAutoConfiguration.class]: Unsatisfied dependency expressed through method 'persistenceExceptionTranslationPostProcessor\ ' parameter 0; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.jbpm.pvm.internal.processengine.SpringHelper] for bean with name 'springHelper' defined in class path resource [spring- jbpm.xml]; nested exception is java.lang.ClassNotFoundException: org.jbpm.pvm.internal.processengine.SpringHelper
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:799)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:540)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:229)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:723)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:536)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:402)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1247)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1236)
at com.ceris.TestApplication.main(TestApplication.java:20)
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:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.jbpm.pvm.internal.processengine.SpringHelper] for bean with name 'springHelper' defined in class path resource [spring-jbpm.xml] ; nested exception is java.lang.ClassNotFoundException: org.jbpm.pvm.internal.processengine.SpringHelper
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1486)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:648)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1614)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:523)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:495)
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors(BeanFactoryUtils.java:265)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1473)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1270)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:886)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:790)
... 28 more
Caused by: java.lang.ClassNotFoundException: org.jbpm.pvm.internal.processengine.SpringHelper
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:469)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1551)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1478)
... 39 more

Project

Maven dependencies are as follows:

<dependency>
      <groupId>org.jbpm</groupId>
      <artifactId>jbpm-bpmn</artifactId>
      <version>1.0-SNAPSHOT</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/src/main/resources/lib/jbpm-bpmn.jar</systemPath>
  </dependency>

Solution

In the spring-boot-maven-plugin plug-in setting, add includeSystemScope to true

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.2</version>
    <configuration>
        <includeSystemScope>true</includeSystemScope>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Reason

Maven whose scope is system is not packaged by default.

 <parameter>
        <name>includeSystemScope</name>
        <type>boolean</type>
        <since>1.4.0</since>
        <required>false</required>
        <editable>true</editable>
        <description>Include system scoped dependencies.</description>
</parameter>

Note: Springboot’s maven packaging plug-in will only scan the path under the current module and will not package external jars under the project paths of other modules. Third-party packages need to be put into the project.

Extension

Scope of Maven dependencies

Sometimes, in addition to the coordinates of the target jar package, the dependency information also has a scope setting, which is the scope of the dependency. There are several optional values for the dependency range. The commonly used ones are: compile, test, and provided. Of course, there are also the less commonly used runtime, system…

compile: Default scope, valid for compilation and test running

provided: valid when compiling and testing

runtime: Valid during testing and runtime

test: only valid during testing

system: valid when compiling and testing, associated with the native system, poor portability

Dependency scope transitivity

The scope of dependencies is also transitive (inheritance). When the scope of the current project and the referenced resource configuration are different, the following relationship exists:

Life cycle

Maven has 3 built-in build lifecycles:

clean – Clean build output, including generated compiled classes, JAR files, etc.
default – compiles the source code and handles everything related to packaging the project
site – Generate documentation for the project

Clean life cycle

The Clean life cycle consists of three stages:

pre-clean performs some work that needs to be done before clean

clean removes all files generated by the previous build

post-clean performs some work that needs to be completed immediately after clean

Default life cycle

Each time a command is executed, the commands before this command will be executed until this command. For example, if you execute the test command, all instructions before test will be executed in sequence until test, and those after test will not be executed. The same goes for other lifecycles.

validate: Verify that the project is correct and that all necessary information is available to complete the project build process.
initialize: Initialize the build state, such as setting property values.
generate-sources: Generates any source code included in the compilation phase.
process-sources (process source code): Process source code, for example, filter arbitrary values.
generate-resources (generate resource files): Generate resource files that will be included in the project package.
process-resources (process resource files): Copy and process resources to the target directory, best prepared for the packaging phase.
compile: Compile the source code of the project.
process-classes (processing class files): Process files generated by compilation, such as bytecode improvement and optimization of Java class files.
generate-test-sources: Generates any test sources included in the compilation phase.
process-test-sources (process test sources): Process test sources, for example, filtering arbitrary values.
generate-test-resources (generate test resource files): Create resource files for tests.
process-test-resources (process test resource files): Copy and process test resources to the target directory.
test-compile (compile test source code): Compile the test source code to the test target directory.
process-test-classes (process test class files): Process files generated by test source code compilation.
test: Run tests using a suitable unit testing framework (Juint is one of them).
prepare-package: Perform any necessary operations to prepare for packaging before actual packaging.
package: Package the compiled code into a distributable format file, such as a JAR, WAR or EAR file.
pre-integration-test (before integration test): Perform necessary actions before executing integration test. For example, build the required environment.
integration-test (integration test): Process and deploy the project into an environment where integration tests can be run.
post-integration-test (post-integration test): Perform necessary actions after the execution of the integration test is completed. For example, clean up the integration test environment.
verify: Run arbitrary checks to verify that the project package is valid and meets quality standards.
install: Install the project package to the local warehouse so that the project package can be used as a dependency for other local projects.
deploy: Copy the final project package to the remote warehouse to share it with other developers and projects.

Site life cycle

pre-site performs some work that needs to be done before generating site documentation

site generates site documentation for the project

post-site performs some work that needs to be done after generating the site documentation and preparing it for deployment

site-deploy deploys the generated site documents to a specific server. The site stage and site-deploy are often used here.
stage is used to generate and publish Maven sites. This is a very powerful function of Maven. Manager prefers it. Documents and statistical data are automatically generated, which is very nice.

Wild horses are also dust, living things blow each other with their breath