Repository: quarkusio/quarkus
Issue: Changing pom file in dev mode can result in changes not being applied

If you change the pom file in dev mode the process is restarted, but if you had made changed to the source and not refreshed the browser these changes will not be applied until you touch the relevant files. This has bitten me on live demos.

Changed files:
devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java, integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java

diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
index 46ce6ec9bdb..3bee994e027 100644
--- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
+++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
@@ -310,7 +310,7 @@ public void execute() throws MojoFailureException, MojoExecutionException {
 
             DevModeRunner runner = new DevModeRunner(args);
 
-            runner.prepare();
+            runner.prepare(false);
             Map<Path, Long> pomFiles = readPomFileTimestamps(runner);
             runner.run();
             long nextCheck = System.currentTimeMillis() + 100;
@@ -324,18 +324,19 @@ public void execute() throws MojoFailureException, MojoExecutionException {
                     if (!runner.process.isAlive()) {
                         return;
                     }
-                    boolean changed = false;
+                    final Set<Path> changed = new HashSet<>();
                     for (Map.Entry<Path, Long> e : pomFiles.entrySet()) {
                         long t = Files.getLastModifiedTime(e.getKey()).toMillis();
                         if (t > e.getValue()) {
-                            changed = true;
+                            changed.add(e.getKey());
                             pomFiles.put(e.getKey(), t);
                         }
                     }
-                    if (changed) {
+                    if (!changed.isEmpty()) {
+                        getLog().info("Changes detected to " + changed + ", restarting dev mode");
                         DevModeRunner newRunner = new DevModeRunner(args);
                         try {
-                            newRunner.prepare();
+                            newRunner.prepare(true);
                         } catch (Exception e) {
                             getLog().info("Could not load changed pom.xml file, changes not applied", e);
                             continue;
@@ -368,19 +369,23 @@ private void handleAutoCompile() throws MojoExecutionException {
 
         //if the user did not compile we run it for them
         if (compileNeeded) {
-            // compile the Kotlin sources if needed
-            final String kotlinMavenPluginKey = ORG_JETBRAINS_KOTLIN + ":" + KOTLIN_MAVEN_PLUGIN;
-            final Plugin kotlinMavenPlugin = project.getPlugin(kotlinMavenPluginKey);
-            if (kotlinMavenPlugin != null) {
-                executeCompileGoal(kotlinMavenPlugin, ORG_JETBRAINS_KOTLIN, KOTLIN_MAVEN_PLUGIN);
-            }
+            triggerCompile();
+        }
+    }
 
-            // Compile the Java sources if needed
-            final String compilerPluginKey = ORG_APACHE_MAVEN_PLUGINS + ":" + MAVEN_COMPILER_PLUGIN;
-            final Plugin compilerPlugin = project.getPlugin(compilerPluginKey);
-            if (compilerPlugin != null) {
-                executeCompileGoal(compilerPlugin, ORG_APACHE_MAVEN_PLUGINS, MAVEN_COMPILER_PLUGIN);
-            }
+    private void triggerCompile() throws MojoExecutionException {
+        // compile the Kotlin sources if needed
+        final String kotlinMavenPluginKey = ORG_JETBRAINS_KOTLIN + ":" + KOTLIN_MAVEN_PLUGIN;
+        final Plugin kotlinMavenPlugin = project.getPlugin(kotlinMavenPluginKey);
+        if (kotlinMavenPlugin != null) {
+            executeCompileGoal(kotlinMavenPlugin, ORG_JETBRAINS_KOTLIN, KOTLIN_MAVEN_PLUGIN);
+        }
+
+        // Compile the Java sources if needed
+        final String compilerPluginKey = ORG_APACHE_MAVEN_PLUGINS + ":" + MAVEN_COMPILER_PLUGIN;
+        final Plugin compilerPlugin = project.getPlugin(compilerPluginKey);
+        if (compilerPlugin != null) {
+            executeCompileGoal(compilerPlugin, ORG_APACHE_MAVEN_PLUGINS, MAVEN_COMPILER_PLUGIN);
         }
     }
 
@@ -494,7 +499,10 @@ class DevModeRunner {
         /**
          * Attempts to prepare the dev mode runner.
          */
-        void prepare() throws Exception {
+        void prepare(final boolean triggerCompile) throws Exception {
+            if (triggerCompile) {
+                triggerCompile();
+            }
             if (debug == null) {
                 // debug mode not specified
                 // make sure 5005 is not used, we don't want to just fail if something else is using it
diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
index ef54583420a..277b8b46ebd 100644
--- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
+++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java
@@ -94,6 +94,41 @@ public void testThatTheApplicationIsReloadedOnJavaChange() throws MavenInvocatio
                 .atMost(1, TimeUnit.MINUTES).until(() -> DevModeTestUtils.getHttpResponse("/app/hello").contains("carambar"));
     }
 
+    @Test
+    public void testThatSourceChangesAreDetectedOnPomChange() throws Exception {
+        testDir = initProject("projects/classic", "projects/project-classic-run-src-and-pom-change");
+        runAndCheck();
+
+        // Edit a Java file too
+        final File javaSource = new File(testDir, "src/main/java/org/acme/HelloResource.java");
+        final String uuid = UUID.randomUUID().toString();
+        filter(javaSource, Collections.singletonMap("return \\"hello\\";", "return \\"hello " + uuid + "\\";"));
+
+        // edit the application.properties too
+        final File applicationProps = new File(testDir, "src/main/resources/application.properties");
+        filter(applicationProps, Collections.singletonMap("greeting=bonjour", "greeting=" + uuid + ""));
+
+        // Now edit the pom.xml to trigger the dev mode restart
+        final File pomSource = new File(testDir, "pom.xml");
+        filter(pomSource, Collections.singletonMap("<!-- insert test dependencies here -->",
+                "        <dependency>\\n" +
+                        "            <groupId>io.quarkus</groupId>\\n" +
+                        "            <artifactId>quarkus-smallrye-openapi</artifactId>\\n" +
+                        "        </dependency>"));
+
+        // Wait until we get the updated responses
+        await()
+                .pollDelay(100, TimeUnit.MILLISECONDS)
+                .atMost(1, TimeUnit.MINUTES)
+                .until(() -> DevModeTestUtils.getHttpResponse("/app/hello").contains("hello " + uuid));
+
+        await()
+                .pollDelay(100, TimeUnit.MILLISECONDS)
+                .atMost(1, TimeUnit.MINUTES)
+                .until(() -> DevModeTestUtils.getHttpResponse("/app/hello/greeting").contains(uuid));
+
+    }
+
     @Test
     public void testThatTheApplicationIsReloadedOnPomChange() throws MavenInvocationException, IOException {
         testDir = initProject("projects/classic", "projects/project-classic-run-pom-change");