diff --git a/flow-tests/pom.xml b/flow-tests/pom.xml
index a316d648d86..873393c636d 100644
--- a/flow-tests/pom.xml
+++ b/flow-tests/pom.xml
@@ -46,7 +46,6 @@
false
0
true
-
@@ -229,7 +228,6 @@
${vaadin.devmode.vite.options}
${vaadin.frontend.hotdeploy}
- ${vaadin.frontend.hotdeploy.dependencies}
diff --git a/flow-tests/test-live-reload-multimodule/ui/pom.xml b/flow-tests/test-live-reload-multimodule/ui/pom.xml
index cef972c46ec..a241bd03286 100644
--- a/flow-tests/test-live-reload-multimodule/ui/pom.xml
+++ b/flow-tests/test-live-reload-multimodule/ui/pom.xml
@@ -14,7 +14,6 @@
war
true
- ../library
diff --git a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ExternalDependencyWatcher.java b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ExternalDependencyWatcher.java
index a9ea7bad05c..a197ca5f369 100644
--- a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ExternalDependencyWatcher.java
+++ b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/ExternalDependencyWatcher.java
@@ -30,6 +30,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
import com.vaadin.flow.server.InitParameters;
import com.vaadin.flow.server.VaadinContext;
@@ -44,25 +45,48 @@ public ExternalDependencyWatcher(VaadinContext context,
File jarFrontendResourcesFolder) {
ApplicationConfiguration config = ApplicationConfiguration.get(context);
- String hotdeployDependencies = config.getStringProperty(
+ String hotdeployDependenciesProperty = config.getStringProperty(
InitParameters.FRONTEND_HOTDEPLOY_DEPENDENCIES, null);
List hotdeployDependencyFolders = new ArrayList<>();
- if (hotdeployDependencies != null) {
- for (String folder : hotdeployDependencies.split(",")) {
+ File projectFolder = config.getProjectFolder();
+ if (hotdeployDependenciesProperty != null) {
+ for (String folder : hotdeployDependenciesProperty.split(",")) {
if (!folder.isBlank()) {
hotdeployDependencyFolders.add(folder.trim());
}
}
+ } else {
+ File pomFile = new File(projectFolder, "pom.xml");
+ File parentPomFile = MavenUtils
+ .getParentPomOfMultiModuleProject(pomFile);
+ if (parentPomFile != null) {
+ Document parentPom = MavenUtils.parsePomFile(parentPomFile);
+ if (parentPom != null) {
+ Path currentPomToParentPomPath = pomFile.getParentFile()
+ .toPath()
+ .relativize(parentPomFile.getParentFile().toPath());
+ hotdeployDependencyFolders = MavenUtils
+ .getModuleFolders(parentPom).stream()
+ .map(folder -> currentPomToParentPomPath
+ + File.separator + folder)
+ .toList();
+ }
+ }
}
for (String hotdeployDependencyFolder : hotdeployDependencyFolders) {
- Path moduleFolder = config.getProjectFolder().toPath()
- .resolve(hotdeployDependencyFolder);
+ Path moduleFolder = projectFolder.toPath()
+ .resolve(hotdeployDependencyFolder).normalize();
+ if (moduleFolder.equals(projectFolder.toPath())) {
+ // Don't watch the active module
+ continue;
+ }
Path metaInf = moduleFolder
.resolve(Path.of("src", "main", "resources", "META-INF"));
if (!watchDependencyFolder(metaInf.toFile(),
- jarFrontendResourcesFolder)) {
+ jarFrontendResourcesFolder)
+ && hotdeployDependenciesProperty != null) {
getLogger().warn("No folders to watch were found in "
+ metaInf.normalize().toAbsolutePath()
+ ". This should be the META-INF folder that contains either frontend or resources/frontend");
diff --git a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/MavenUtils.java b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/MavenUtils.java
index 827cb3cc76e..142c972b3a0 100644
--- a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/MavenUtils.java
+++ b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/MavenUtils.java
@@ -4,6 +4,9 @@
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.Stream.Builder;
@@ -11,7 +14,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -80,7 +82,7 @@ public static Document parsePomFile(File pomFile) {
* @return Text content of the first mach or null if not found.
*/
static String getFirstElementTextByName(Node parent, String nodeName) {
- return findChild(parent, nodeName).map(node -> node.getTextContent())
+ return findChild(parent, nodeName).map(Node::getTextContent)
.orElse(null);
}
@@ -95,7 +97,7 @@ public static String getGroupId(Document pom) {
String groupId = getFirstElementTextByName(pom.getDocumentElement(),
"groupId");
if (groupId == null) {
- groupId = findChild(pom.getDocumentElement(), "parent")
+ groupId = findParentTag(pom)
.map(parentNode -> getFirstElementTextByName(parentNode,
"groupId"))
.orElse(null);
@@ -103,6 +105,10 @@ public static String getGroupId(Document pom) {
return groupId;
}
+ private static Optional findParentTag(Document pom) {
+ return findChild(pom.getDocumentElement(), "parent");
+ }
+
/**
* Finds the artifact id for the given pom file.
*
@@ -115,6 +121,18 @@ public static String getArtifactId(Document pom) {
"artifactId");
}
+ private static Optional getParentArtifactId(Document pom) {
+ return findParentTag(pom)
+ .flatMap(parentNode -> findChild(parentNode, "artifactId"))
+ .map(Node::getTextContent);
+ }
+
+ private static Optional getParentRelativePath(Document pom) {
+ return findParentTag(pom)
+ .flatMap(parentNode -> findChild(parentNode, "relativePath"))
+ .map(Node::getTextContent);
+ }
+
private static Optional findChild(Node node, String tagname) {
return findChildren(node, tagname).findFirst();
}
@@ -132,4 +150,88 @@ private static Stream findChildren(Node node, String tagname) {
return builder.build();
}
+ /**
+ * Gets the parent pom location for the given pom file, if the given pom
+ * file is part of a multi module project.
+ *
+ * @param pomFile
+ * the pom file
+ * @return the location of the parent pom file or {@code null} if the given
+ * pom file does not have a parent inside the same multi module
+ * project
+ */
+ public static File getParentPomOfMultiModuleProject(File pomFile) {
+ Document pom = parsePomFile(pomFile);
+ if (pom == null) {
+ return null;
+ }
+ Optional parent = getParentArtifactId(pom);
+ if (!parent.isPresent()) {
+ return null;
+ }
+
+ File pomFolder = pomFile.getParentFile();
+ File parentPomFile = getParentRelativePath(pom)
+ .map(relativePath -> new File(pomFolder, relativePath))
+ .map(relativePath -> {
+ if (!relativePath.isFile()) {
+ // relative path can refer to a folder
+ relativePath = new File(relativePath, "pom.xml");
+ }
+ return relativePath;
+ }).orElse(new File(pomFolder.getParentFile(), "pom.xml"));
+
+ Document parentFolderPom = parsePomFile(parentPomFile);
+ if (parentFolderPom == null) {
+ return null;
+ }
+ String parentFolderArtifactId = getArtifactId(parentFolderPom);
+
+ if (Objects.equals(parent.get(), parentFolderArtifactId)) {
+ try {
+ return parentPomFile.getCanonicalFile();
+ } catch (IOException e) {
+ return parentPomFile;
+ }
+ }
+ return null;
+
+ }
+
+ /**
+ * Gets a list of the folders containing the sub modules for the given pom
+ * file.
+ *
+ * @param pom
+ * the pom file containing sub modules
+ * @return a list of folders for the sub modules
+ */
+ public static List getModuleFolders(Document pom) {
+ return findChild(pom.getDocumentElement(), "modules").stream()
+ .flatMap(node -> findChildren(node, "module"))
+ .map(Node::getTextContent)
+ .map(possiblyFilename -> removeAfter(possiblyFilename, "/"))
+ .toList();
+ }
+
+ /**
+ * Removes the part of the given string that comes after the (last) instance
+ * of the given delimiter.
+ *
+ * Returns the original string if it does not contain the delimiter.
+ *
+ * @param str
+ * the string to parse
+ * @param delimiter
+ * the delimiter to look for
+ * @return the modified string
+ */
+ private static String removeAfter(String str, String delimiter) {
+ int i = str.lastIndexOf(delimiter);
+ if (i != -1) {
+ return str.substring(0, i);
+ }
+ return str;
+ }
+
}
diff --git a/vaadin-dev-server/src/test/java/com/vaadin/base/devserver/MavenUtilsTest.java b/vaadin-dev-server/src/test/java/com/vaadin/base/devserver/MavenUtilsTest.java
index 98fee80aa54..6459342f3ea 100644
--- a/vaadin-dev-server/src/test/java/com/vaadin/base/devserver/MavenUtilsTest.java
+++ b/vaadin-dev-server/src/test/java/com/vaadin/base/devserver/MavenUtilsTest.java
@@ -2,11 +2,12 @@
import java.io.File;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -17,8 +18,16 @@ public class MavenUtilsTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
+ private File mavenFolder;
+
+ @Before
+ public void setupPoms() throws Exception {
+ URL mavenTestResourceDirectory = getClass().getResource("maven");
+ this.mavenFolder = Path.of(mavenTestResourceDirectory.toURI()).toFile();
+ }
+
@Test
- public void basicInformationForStandalonePom() throws IOException {
+ public void basicInformationForStandalonePom() throws Exception {
File pomXml = getPomXml("pom-standalone.xml");
Document parse = MavenUtils.parsePomFile(pomXml);
Assert.assertEquals("this.group", MavenUtils.getGroupId(parse));
@@ -27,21 +36,64 @@ public void basicInformationForStandalonePom() throws IOException {
}
@Test
- public void basicInformationForPomWithParent() throws IOException {
- File pomXml = getPomXml("pom-with-parent.xml");
+ public void basicInformationForPomWithParent() throws Exception {
+ File pomXml = getPomXml("standard-multimodule/module1/pom.xml");
Document parse = MavenUtils.parsePomFile(pomXml);
Assert.assertEquals("this.group", MavenUtils.getGroupId(parse));
Assert.assertEquals("this-the-artifact",
MavenUtils.getArtifactId(parse));
}
+ @Test
+ public void detectsPomIsPartOfASimpleMultimoduleProject() throws Exception {
+ File parent = getPomXml("standard-multimodule/pom.xml");
+ Assert.assertEquals(parent, MavenUtils.getParentPomOfMultiModuleProject(
+ getPomXml("standard-multimodule/module1/pom.xml")));
+ }
+
+ @Test
+ public void detectsPomWithRelativePathIsPartOfASimpleMultimoduleProject()
+ throws Exception {
+ File parent = getPomXml("standard-multimodule/pom.xml");
+ Assert.assertEquals(parent, MavenUtils.getParentPomOfMultiModuleProject(
+ getPomXml("standard-multimodule/module2/pom.xml")));
+ }
+
+ @Test
+ public void detectsPomIsPartOfAComplexMultimoduleProject()
+ throws Exception {
+ File parent = getPomXml("complex-multimodule/pom-parent.xml");
+ File parentPomOfMultiModuleProject = MavenUtils
+ .getParentPomOfMultiModuleProject(getPomXml(
+ "complex-multimodule/module1/pom-with-parent.xml"));
+ Assert.assertEquals(parent, parentPomOfMultiModuleProject);
+ }
+
+ @Test
+ public void findsModulesInSimpleMultiModulePom() throws Exception {
+ File pomXml = getPomXml("standard-multimodule/pom.xml");
+ Document pom = MavenUtils.parsePomFile(pomXml);
+ Assert.assertEquals(List.of("module1", "module2"),
+ MavenUtils.getModuleFolders(pom));
+ }
+
+ @Test
+ public void findsModulesInComplexMultiModulePom() throws Exception {
+ File pomXml = getPomXml("complex-multimodule/pom-parent.xml");
+ Document pom = MavenUtils.parsePomFile(pomXml);
+ Assert.assertEquals(List.of("module1", "module2"),
+ MavenUtils.getModuleFolders(pom));
+ }
+
+ @Test
+ public void findsNoModulesInStandalonePom() throws Exception {
+ File pomXml = getPomXml("pom-standalone.xml");
+ Document pom = MavenUtils.parsePomFile(pomXml);
+ Assert.assertEquals(List.of(), MavenUtils.getModuleFolders(pom));
+ }
+
private File getPomXml(String filename) throws IOException {
- File pomXml = temporaryFolder.newFile(filename);
- FileUtils.write(pomXml,
- IOUtils.toString(getClass().getResource("maven/" + filename),
- StandardCharsets.UTF_8),
- StandardCharsets.UTF_8);
- return pomXml;
+ return new File(mavenFolder, filename);
}
}
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-with-parent.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/module1/pom-with-parent.xml
similarity index 83%
rename from vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-with-parent.xml
rename to vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/module1/pom-with-parent.xml
index 61e69e7e51a..6c34e3152c4 100644
--- a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-with-parent.xml
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/module1/pom-with-parent.xml
@@ -4,8 +4,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
+ parent-artifact
this.group
1.7.2-SNAPSHOT
+ ../pom-parent.xml
this-the-artifact
Something something
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/module2/pom.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/module2/pom.xml
new file mode 100644
index 00000000000..f8ed761e505
--- /dev/null
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/module2/pom.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+ parent-artifact
+ this.group
+ 1.7.2-SNAPSHOT
+ ../pom-parent.xml
+
+ another-artifact
+ Something something
+
+
+
+
+
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/pom-parent.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/pom-parent.xml
new file mode 100644
index 00000000000..614a5f9fa50
--- /dev/null
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/complex-multimodule/pom-parent.xml
@@ -0,0 +1,16 @@
+
+
+ 4.0.0
+ this.group
+ parent-artifact
+ 1.7.2-SNAPSHOT
+ Something something parent
+ pom
+
+ module1/pom-with-parent.xml
+ module2
+
+
+
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-standalone.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-standalone.xml
index 947ec0918fc..ff7eb03bda1 100644
--- a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-standalone.xml
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/pom-standalone.xml
@@ -8,7 +8,4 @@
1.7.2-SNAPSHOT
Something something
-
-
-
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/module1/pom.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/module1/pom.xml
new file mode 100644
index 00000000000..6b974ec69a5
--- /dev/null
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/module1/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ parent-artifact
+ this.group
+ 1.7.2-SNAPSHOT
+
+ this-the-artifact
+ Something something
+
+
+
+
+
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/module2/pom.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/module2/pom.xml
new file mode 100644
index 00000000000..4f4396f620b
--- /dev/null
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/module2/pom.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+ parent-artifact
+ this.group
+ 1.7.2-SNAPSHOT
+ ..
+
+ another-artifact
+ Something something
+
+
+
+
+
diff --git a/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/pom.xml b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/pom.xml
new file mode 100644
index 00000000000..a6cd1b1dc8b
--- /dev/null
+++ b/vaadin-dev-server/src/test/resources/com/vaadin/base/devserver/maven/standard-multimodule/pom.xml
@@ -0,0 +1,16 @@
+
+
+ 4.0.0
+ this.group
+ parent-artifact
+ 1.7.2-SNAPSHOT
+ Something something parent
+ pom
+
+ module1
+ module2
+
+
+