Run mvn spring-boot:run from parent module? - spring-boot

I have a multi-module maven project like this:
my-parent
--my-domain
--my-service
--my-app <<< this is a Spring Boot module
I want to run mvn spring-boot:run command directly from the parent module without having to cd into the 'my-app' directory first.
I figure this is related to configuration of the spring-boot-maven-plugin but I can't seem to get it right.
I have tried the following:
Use spring-boot-starter-parent and otherwise default config with spring-boot-maven-plugin included in plugins section of my-app.
Running mvn spring-boot:run from the parent results in:
Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.4.2.RELEASE:run (default-cli) on project my-parent: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1] in the parent module
Do NOT use spring-boot-starter-parent.
Define spring-boot-dependencies in depManagement as described elewhere. Define spring-boot-maven-plugin in pluginManagement section of my-parent and include the plugin in plugins section of my-app module.
Running mvn spring-boot:run from the parent results in same error as #1:
Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.4.2.RELEASE:run (default-cli) on project my-parent: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1]
Do NOT use spring-boot-starter-parent.
Define spring-boot-dependencies in depManagement as described elewhere. Define spring-boot-maven-plugin in plugins section of my-app.
Running mvn spring-boot:run from the parent results in:
No plugin found for prefix 'spring-boot' in the current project and in the plugin groups
In all cases described above, running mvn spring-boot:run from the my-app directory works fine.
I figure there should be a way to make this work. In a traditional non-Boot Spring project it was fairly simple to configure tomcat7 plugin such that i could run mvn tomcat7:run-war from the parent and the webapp sub-module would start as expected

You can do it by adding following In parent pom:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
And in your
In my-app (Spring Boot module) pom:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<skip>false</skip>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
Now you can do execute in project root:
mvn -pl my-app -am spring-boot:run
Additional references:
spring-boot:run hot reload with multi module maven project · Issue #3436 · spring-projects/spring-boot · GitHub: in particular, this comment.

spring-boot maven plugin configuration options:
skip: skips the execution of sprint-boot:run [default: false]
fork: Flag to indicate if the run processes should be forked [default: true]
see spring-boot maven plugin parameters
maven options:
-pl, --projects: Comma-delimited list of specified reactor projects to build instead of all projects. A project can be specified by [groupId]:artifactId or by its relative path
-am, --also-make: If project list is specified, also build projects required by the list
see maven CLI options

Related

Run two maven modules using mvn tomcat7:run

I've got the following project layout:
web_root
- pom.xml -> packaging: pom
- web_relay
- pom.xml -> packaging: war
- src/...
- web_service
- pom.xml -> packaging: war
- src/...
My web_root's pom.xml has is the superproject and contains two modules: web_relay and web_service.
For reasons unknown someone split these projects rather arbitrarily. I've been trying to merge these projects under one maven superproject.
I can run each of the web_relay and web_service projects using mvn tomcat7:run. However, I need both running on the same tomcat server. When I run tomcat7:run on web_root, however, it only runs the tomcat server for one of the two modules.
How can I get mvn tomcat7:run to run both wars?
The approach from How to use maven plugin tomcat7:run with multiple contexts (WARs)? works only if I mvn install my dependencies separately and don't include them as modules. If I do include them as modules, mvn will just run tomcat7:run in the first module it finds.
Run the war's from a dummy module, listing all dependencies as 'webapps'.
I.e. in the individual pom's, use:
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
And make a new module that launches all dependencies at once
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<webapps>
<webapp>
<groupId>com.company</groupId>
<artifactId>webapp-1</artifactId>
<version>1.0</version>
<type>war</type>
</webapp>
[Add more]
</webapps>
As an alternative, and maybe a better solution in the long run, package all web applications in a single EAR (enterprise archive: https://maven.apache.org/plugins/maven-ear-plugin/), so you can also deploy them in production in a single action.
Tomcat7 does not support EAR deploys, but TomEE does: http://tomee.apache.org/maven/run-mojo.html
And JBoss, too: https://docs.jboss.org/jbossas/7/plugins/maven/latest/run-mojo.html

How to 'mvn jetty:run' from a parent pom?

I have a multi-module project that includes several .war packages. I would like to be able to 'mvn jetty:run' on the parent pom and have each of the sub-modules's .wars deployed on the same embedded jetty instance.
I am able to successfully run 'mvn jetty:run' from each of the the sub-modules, but when I run it on the parent pom it fails and skips the sub-modules.
Trying to run 'mvn jetty:run' from the parent pom results in the following:
[ERROR] Failed to execute goal
org.mortbay.jetty:maven-jetty-plugin:6.1.16:run default-cli) on
project FlashCards_App: Webapp source directory C:\dev\sour
ce_code\FlashCards_App\src\main\webapp does not exist -> [Help 1]
It's true there is no webapp directory on the parent pom.
Here's an excerpt from my pom. The full file can be found here.
<modules>
<module>FlashCards_Domain</module>
<module>FlashCards_GWT</module>
<module>FlashCards_Service</module>
<module>FlashCards_Service_SpringData</module>
<module>FlashCards_Service_Jpa</module>
<module>FlashCards_WebServices</module>
<module>FlashCards_Struts</module>
<module>FlashCards_Test</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>${jetty.version}</version>
</plugin>
</plugins>
</build>
This is basically the same question asked in 2009 in this post. It's been a few years and I'm wondering if there are any other options available now. The previous post proposes two solutions (1) using cargo plugin and (2) building sister wars from a sub-module.
Your best shot is probably to configure the jetty plugin to run multiple webapps. I'm not sure if it would work from your parent pom though, so you might have to use on of your modules as the "launcher" webapp, or create a "dummy webapp" in your parent project.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.6.v20141205</version>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<webApp>
<contextPath>/</contextPath>
</webApp>
<contextHandlers>
<contextHandler implementation="org.eclipse.jetty.maven.plugin.JettyWebAppContext">
<war>${project.basedir}/app1/target/app1.war</war>
<contextPath>/app1</contextPath>
</contextHandler>
<contextHandler implementation="org.eclipse.jetty.maven.plugin.JettyWebAppContext">
<war>${project.basedir}/app2/target/app2.war</war>
<contextPath>/app2</contextPath>
</contextHandler>
</contextHandlers>
<stopPort>9999</stopPort>
<stopKey>STOP</stopKey>
</configuration>
</plugin>
cd parent_module
mvn jetty:run -pl sub_module
cd parent_module
mvn jetty:run -pl sub_module
To complete #jiahut answer:
$ mvn jetty:run --help
(...)
-am,--also-make If project list is specified, also
build projects required by the
list
-amd,--also-make-dependents If project list is specified, also
build projects that depend on
projects on the list
(...)
-pl,--projects <arg> Comma-delimited list of specified
reactor projects to build instead
of all projects. A project can be
specified by [groupId]:artifactId
or by its relative path
Example from Apache Archiva:
mvn jetty:run -pl :archiva-webapp -am

tomcat-maven-plugin with multi module and war overlay

I have a maven war project (call it projectA) that depends on another maven war (call it projectB). They get integrated using an overlay with the maven-war-plugin. Both projects have the same parent and the same aggregator (different from the parent). I can package the final war successfully without any issue. This is the command I'm running to do that (I'm at the aggregator level when running mvn):
mvn -am -pl projectA package
The reactor build order is parent ➡ projectB ➡ projectA and all is fine.
I'm now trying to use the tomcat-maven-plugin in this build. So I added the tomcat-maven-plugin in the parent pom pluginManagement section and used it in the projectA pom. I'm launching tomcat with:
mvn -am -pl projectA tomcat:run
The reactor build order remains the same. But the tomcat execution is run on projectB (which is also a war) and not on projectA. Actually, projectA build is not even reached.
I've tried with both the org.codehaus.mojo.tomcat-maven-plugin v1.1 and org.apache.tomcat.maven.tomcat6-maven-plugin v2.1, I've found the same behavior.
How can I make tomcat run the final projectA?
Note: The project dependencies are in fact a bit more complicated and there are other sub-projects involved (jars), that's why I'm calling maven with -am (also make).
Ok, so I found a solution. It is to disable the maven-tomcat-plugin for the pojectB, this answer is based on this other question.
Linking the plugin to a specific phase
First I had to link the maven-tomcat-plugin to a phase of my build cycle, so that it is called even if I don't call the plugin directly from the CLI, obviously I choose the integration-test phase. I can now run mvn integration-test -pl projectA to have tomcat being launched with the just build war.
This is how the plugin is declared in the parent:
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat6-maven-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>run-war</id>
<!-- We link this plugin to some non default phase so that we can disable it in some modules. -->
<phase>integration-test</phase>
<goals>
<goal>run-war</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
and in projectA I just make use of it as declared in the parent:
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat6-maven-plugin</artifactId>
</plugin>
</plugin>
</build>
Deactivating the plugin in projectB
Then, in projectB, I link the same plugin (with the same id) to a null/void/empty phase, which ends up disabling the plugin for this project when built for this integration-test phase:
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat6-maven-plugin</artifactId>
<executions>
<execution>
<id>run-war</id>
<!-- We don't want this plugin to be called from another module build -->
<phase/>
</execution>
</executions>
</plugin>
</plugins>
</build>
With that setup, I can now do a complete build (both projectB, projectA and other dependencies) and launch tomcat with the resulting war in a single run:
mvn -am -pl projectA clean integration-test

Running antrun during war:exploded

For a Maven build I need to copy some files after the exploded directory has been made with the war plugin. Is it possible to run the antrun plugin during/after the war:exploded goal? If so how would I do this? I've tried:
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>war</phase>
<goals>
<goal>exploded</goal>
</goals>
<configuration>
<tasks>
<echo>Running ant task...</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
And several other variation but can't seem to get it to run.
Idealy I'd like the ant task to run if I do a full war:war too but I'll cross this bridge when I come to it.
There are at least two ways to achieve it:
Using direct invocation of plugins
When calling mvn war:exploded oder mvn war:war, you only call a specific goal of a specific plugin. No other plugin is executed. Executions defined in pom.xml are not relevant. As a consequence, you could only call several plugin goals directly, for example mvn war:exploded antrun:run.
But be careful when building several modules: mvn war:exploded antrun:run runs antrun after the war plugin for each module. Whereas mvn war:exploded; mvn antrun:run runs the war plugin for all modules and then antrun for all modules.
Using lifecycle bindings of plugins
When calling mvn pre-integration-test, you call all phases of the default lifecycle up to pre-integration-test. You could define an war plugin execution for goal "exploded" in phase "package" and an antrun execution for goal "run" in phase "pre-integration-test".
There is no phase "war" in the default lifecycle. So your example above won't work with the default lifecycle. And for a custom lifecycle with custom phases, you need custom plugins.

Using Maven shade plugin in a multi module project - NullPointerException

I have a scenario where-in I need to create an uber jar of a multi module maven project including all modules and their dependencies. I tried using maven shade plugin. but it seems to work only when I use it at the module level. If I add the plugin entry in parent pom then the build breaks (it tries to shade the parent pom)
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing null with C:\Projects\foo.bar\target\foobar-0.0.1-SNAPSHOT-shaded.pom
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Error creating shaded jar: null: NullPointerException -> [Help 1]
It does seem to make sense since the <packaging> for the parent maven project is pom.
But there should be some way to create an uber jar for a multi module project... Any ideas people???
You should not be using your parent project's POM file to attempt shading; you should be using a separate aggregator project for this. Parent maven projects are used for inheritance while aggregator projects are used to perform aggregate functions over a group of sub-projects; like shading their JARs together into a uber jar. This project would simply be a pom file at the root directory of your project (the same level as all the sub-modules' folders) which references the sub-projects and has the shade plugin configuration. Make sure the packaing specified for this pom is JAR.
Here is the documentation explaining POM relationships and difference between Aggregation and Inheritance.
Yes ! You can ! :-)
Shade has an implementation problem: it doen't know when is running over pom (not jar or web) project. Pom projects don't generate binary artifacts, then shade doesn't find files to merge, move, etc., throwing NPE.
To solve this problem, create a parent POM from your aggegate-Pom project. Inside it, put the shade definitions and configuration configuring to some profile (eg. alwaysActiveProfiles) and install/deploy it with command:
mvn deploy -P -alwaysActiveProfiles
This command will install this shaded parent without running shade plugin pom (-alwaysActiveProfiles option supress shade plugin execution) and after that, your maven dependent projects will work.
Your shaded parent pom could looks 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>xxxxxxxx</groupId>
<artifactId>web-pom</artifactId>
<name>web-pom</name>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
...
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
...
</dependencies>
<profiles>
<profile>
<id>alwaysActiveProfiles</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Remember that your setting.xml must have alwaysActiveProfiles enabled by default, otherwise shade will not run in your dependences shade-pom projects.
I was having the same problem with version 1.6 of the plugin, I updated to 2.2 and the problem was solved

Resources