From e606e442a4a44969e05b5c4ecbc2c03990f060ec Mon Sep 17 00:00:00 2001 From: Marco Collovati Date: Thu, 21 Nov 2024 11:13:49 +0100 Subject: [PATCH] fix: exclude project maven dependencies from isolated class loader (#20523) If the user project directly or transitively depends on maven artifacts, mojos can fail at runtime because of Maven API loaded from both isolated class loader and maven.api realm. This change prevents maven artifacts from being added to the isolated class loader. --- .../vaadin/flow/plugin/maven/Reflector.java | 12 +++ .../invoker.properties | 17 ++++ .../it/ignore-maven-deps-from-project/pom.xml | 88 +++++++++++++++++++ .../com/vaadin/test/ProjectFlowExtension.java | 20 +++++ .../vaadin/flow/plugin/maven/Reflector.java | 12 +++ 5 files changed, 149 insertions(+) create mode 100644 flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/invoker.properties create mode 100644 flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/pom.xml create mode 100644 flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/src/main/java/com/vaadin/test/ProjectFlowExtension.java diff --git a/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java b/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java index 85f2979c094..b130a235255 100644 --- a/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java +++ b/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -48,6 +49,9 @@ public final class Reflector { public static final String INCLUDE_FROM_COMPILE_DEPS_REGEX = ".*(/|\\\\)(portlet-api|javax\\.servlet-api)-.+jar$"; + private static final Set DEPENDENCIES_GROUP_EXCLUSIONS = Set.of( + "org.apache.maven", "org.codehaus.plexus", "org.slf4j", + "org.eclipse.sisu"); private final URLClassLoader isolatedClassLoader; private Object classFinder; @@ -223,6 +227,10 @@ private static URLClassLoader createIsolatedClassLoader( Map projectDependencies = new HashMap<>(project .getArtifacts().stream() + // Exclude all maven artifacts to prevent class loading clash + // with maven.api class realm + .filter(artifact -> !DEPENDENCIES_GROUP_EXCLUSIONS + .contains(artifact.getGroupId())) .filter(artifact -> artifact.getFile() != null && artifact.getArtifactHandler().isAddedToClasspath() && (Artifact.SCOPE_COMPILE.equals(artifact.getScope()) @@ -238,6 +246,10 @@ private static URLClassLoader createIsolatedClassLoader( if (mojoExecution != null) { mojoExecution.getMojoDescriptor().getPluginDescriptor() .getArtifacts().stream() + // Exclude all maven artifacts to prevent class loading + // clash with maven.api class realm + .filter(artifact -> !DEPENDENCIES_GROUP_EXCLUSIONS + .contains(artifact.getGroupId())) .filter(artifact -> !projectDependencies .containsKey(keyMapper.apply(artifact))) .forEach(artifact -> projectDependencies diff --git a/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/invoker.properties b/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/invoker.properties new file mode 100644 index 00000000000..5aa13827263 --- /dev/null +++ b/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/invoker.properties @@ -0,0 +1,17 @@ +# +# Copyright 2000-2024 Vaadin Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +invoker.goals=clean package diff --git a/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/pom.xml b/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/pom.xml new file mode 100644 index 00000000000..56131acf0c8 --- /dev/null +++ b/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + com.vaadin.test.maven + resources-from-project + 1.0 + jar + + + Tests that plugin dependencies do not override resources from project artifacts. + + + + UTF-8 + 17 + ${maven.compiler.release} + ${maven.compiler.release} + true + + @project.version@ + 3.9.9 + + + + + com.vaadin + flow-server + ${flow.version} + + + com.vaadin + flow-client + ${flow.version} + + + org.apache.maven + maven-artifact + ${maven.version} + + + org.apache.maven + maven-core + ${maven.version} + + + org.apache.maven + maven-plugin-api + ${maven.version} + + + org.slf4j + slf4j-simple + 2.0.16 + + + org.codehaus.plexus + plexus-build-api + 1.2.0 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + + com.vaadin + flow-maven-plugin + ${flow.version} + + + + prepare-frontend + build-frontend + + + + + + + + diff --git a/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/src/main/java/com/vaadin/test/ProjectFlowExtension.java b/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/src/main/java/com/vaadin/test/ProjectFlowExtension.java new file mode 100644 index 00000000000..fd5304d4b88 --- /dev/null +++ b/flow-plugins/flow-maven-plugin/src/it/ignore-maven-deps-from-project/src/main/java/com/vaadin/test/ProjectFlowExtension.java @@ -0,0 +1,20 @@ +package com.vaadin.test; + +import java.util.List; + +import com.vaadin.flow.server.frontend.Options; +import com.vaadin.flow.server.frontend.TypeScriptBootstrapModifier; +import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner; + +/** + * Hello world! + */ +public class ProjectFlowExtension implements TypeScriptBootstrapModifier { + + @Override + public void modify(List bootstrapTypeScript, Options options, + FrontendDependenciesScanner frontendDependenciesScanner) { + System.out.println("ProjectFlowExtension"); + bootstrapTypeScript.add("(window as any).testProject=1;"); + } +} diff --git a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java index 05ac26687f6..b5ee45c4408 100644 --- a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java +++ b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/Reflector.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -48,6 +49,9 @@ public final class Reflector { public static final String INCLUDE_FROM_COMPILE_DEPS_REGEX = ".*(/|\\\\)(portlet-api|javax\\.servlet-api)-.+jar$"; + private static final Set DEPENDENCIES_GROUP_EXCLUSIONS = Set.of( + "org.apache.maven", "org.codehaus.plexus", "org.slf4j", + "org.eclipse.sisu"); private final URLClassLoader isolatedClassLoader; private Object classFinder; @@ -223,6 +227,10 @@ private static URLClassLoader createIsolatedClassLoader( Map projectDependencies = new HashMap<>(project .getArtifacts().stream() + // Exclude all maven artifacts to prevent class loading clash + // with maven.api class realm + .filter(artifact -> !DEPENDENCIES_GROUP_EXCLUSIONS + .contains(artifact.getGroupId())) .filter(artifact -> artifact.getFile() != null && artifact.getArtifactHandler().isAddedToClasspath() && (Artifact.SCOPE_COMPILE.equals(artifact.getScope()) @@ -238,6 +246,10 @@ private static URLClassLoader createIsolatedClassLoader( if (mojoExecution != null) { mojoExecution.getMojoDescriptor().getPluginDescriptor() .getArtifacts().stream() + // Exclude all maven artifacts to prevent class loading + // clash with maven.api class realm + .filter(artifact -> !DEPENDENCIES_GROUP_EXCLUSIONS + .contains(artifact.getGroupId())) .filter(artifact -> !projectDependencies .containsKey(keyMapper.apply(artifact))) .forEach(artifact -> projectDependencies