Maven jetty plugin - automatic reload using a multi-module project
Asked Answered
L

3

9

I am developing a Java web application, using a multi-module maven project. The project setup is the following:

  • pom.xml Main maven project, that includes the following modules:
    • persistence: Entity classes and DAOs
    • business: Service definition and implementation
    • webapp: Apache wicket web application

The dependency hierarchy is the following: webapp depends on business, which depends on persistence.

I am also using the Jetty Maven Plugin to run the web application locally using mvn -pl webapp jetty:run inside the directory with the main pom.xml. When developing the application, When making code changes, I want the jetty server to restart and reload the modified code files automatically. This works fine when I am modifying files inside the webapp module, but does not work when I am modifying a file inside another module, such persistence or business.

The Maven Jetty Plugin is configured inside webapp/pom.xml as follows:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.2.2.v20140723</version>
    <configuration>
        <reload>automatic</reload>
        <scanIntervalSeconds>1</scanIntervalSeconds>
        <webApp>
            <extraClasspath>../business/target/classes/;../persistence/target/classes/</extraClasspath>
        </webApp>
        <scanTargets>
            <scanTarget>../business/target/classes</scanTarget>
            <scanTarget>../persistence/target/classes</scanTarget>
        </scanTargets>
</plugin>

I followed the instructions of this answer. The <scanTarget> tags work fine, since jetty gets restarted when I modify a file inside business or persistence. However, the <extraClasspath> does not work since the modified files are not loaded by jetty. The linked answer uses the <webAppConfig> tag. However, I am using the <webApp> tag as specified in the documentation of the plugin (I also tried the old <webAppConfig> tag, which lead to the same results).

My question is: How to configure the Jetty Maven Plugin for a multi-module project, such that it reloads modified files from other modules?

Longing answered 8/9, 2014 at 13:35 Comment(0)
L
4

Using trial and error, I found a solution. The problem is that jetty is executed using from the parent pom using

mvn -pl webapp jetty:run

The command is called from the directory of the main pom, thus jetty cannot resolve the relative paths inside the extraClasspath correctly. When executing the jetty:run goal inside the webapp directory, all modified classes are loaded correctly.


I assume the scanTargets are working correctly even when using mvn -pl webapp jetty:run, because the relative paths get resolved during the execution of the plugin (with the correct working directory). Jetty outputs the scan targets on startup:

[INFO] Added extra scan target:C:\PathToProject\business\target\classes
[INFO] Added extra scan target:C:\PathToProject\persistence\target\classes

However, the <extraClasspath>property is part of the <webApp> property, which is an instance of the org.eclipse.jetty.webapp.WebAppContext class. I assume that this instance is passed to jetty directly and that the extraClasspath property is accessed by jetty when it is already started.

Longing answered 8/9, 2014 at 21:12 Comment(2)
Do you have any problem with the PermGen space using this configuration?Radioactivity
@Radioactivity I've had some problems that jetty ran out of memory, but I fixed them by creating a environment variable called MAVEN_OPTS with value -Xmx1024m -Xms512m -XX:MaxPermSize=1024m (see https://mcmap.net/q/1315233/-maven-jetty-plugin-outofmemoryerror-when-sharing-instance-between-two-web-apps for details)Longing
S
5

To force the reload anytime a submodule is changed you can use the following options

1 - Static module names and scan targets

You can define as scan targets the target directory for each module

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>${jetty.plugin.version}</version>
    <configuration>
        <scanIntervalSeconds>${jetty.scanInterval}</scanIntervalSeconds>
        <scanTargets>
            <scanTarget>module-name/target/classes</scanTarget>
            <scanTarget>module-name2/target/classes</scanTarget>
        </scanTargets>
    </configuration>
</plugin>

2 - Dinamic module names and scan targets (recommended) This uses RegEx to find the compilation target for other modules, on the following example, we are reloading the application everytime a class is compiled on any module

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>${jetty.plugin.version}</version>
    <configuration>
        <scanIntervalSeconds>${jetty.scanInterval}</scanIntervalSeconds>
        <scanTargetPatterns>
            <scanTargetPattern>
                <directory>${project.basedir}</directory>
                <includes>
                    <include>**/target/classes/**/*.class</include>
                </includes>
            </scanTargetPattern>
        </scanTargetPatterns>
    </configuration>
</plugin>
Scriabin answered 25/9, 2014 at 15:51 Comment(0)
L
4

Using trial and error, I found a solution. The problem is that jetty is executed using from the parent pom using

mvn -pl webapp jetty:run

The command is called from the directory of the main pom, thus jetty cannot resolve the relative paths inside the extraClasspath correctly. When executing the jetty:run goal inside the webapp directory, all modified classes are loaded correctly.


I assume the scanTargets are working correctly even when using mvn -pl webapp jetty:run, because the relative paths get resolved during the execution of the plugin (with the correct working directory). Jetty outputs the scan targets on startup:

[INFO] Added extra scan target:C:\PathToProject\business\target\classes
[INFO] Added extra scan target:C:\PathToProject\persistence\target\classes

However, the <extraClasspath>property is part of the <webApp> property, which is an instance of the org.eclipse.jetty.webapp.WebAppContext class. I assume that this instance is passed to jetty directly and that the extraClasspath property is accessed by jetty when it is already started.

Longing answered 8/9, 2014 at 21:12 Comment(2)
Do you have any problem with the PermGen space using this configuration?Radioactivity
@Radioactivity I've had some problems that jetty ran out of memory, but I fixed them by creating a environment variable called MAVEN_OPTS with value -Xmx1024m -Xms512m -XX:MaxPermSize=1024m (see https://mcmap.net/q/1315233/-maven-jetty-plugin-outofmemoryerror-when-sharing-instance-between-two-web-apps for details)Longing
R
3

The following configuration works for me

    <!-- To launch embded jetty server -->
<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>7.4.2.v20110526</version>


    <configuration>
        <scanIntervalSeconds>3</scanIntervalSeconds>
        <webAppConfig>
            <contextPath>/${project.name}</contextPath>
            <extraClasspath>target/classes;../services/target/classes;../util/target/classes</extraClasspath>
        </webAppConfig>
        <scanTargets>
            <scanTarget>target/classes</scanTarget>
            <scanTarget>../services/target/classes</scanTarget>
            <scanTarget>../util/target/classes</scanTarget>
        </scanTargets>
    </configuration>

</plugin>
Radioactivity answered 8/9, 2014 at 15:4 Comment(1)
I tried the exactly same configuration (i.e. version of the jetty plugin) and it did not work. However, because I new this configuration did work for you, I tried calling mvn jetty:run inside the webapp directory (see my answer). +1 and thanks for helping me find a solution :)Longing

© 2022 - 2024 — McMap. All rights reserved.