From 84ec74b819c6a1c9ed0080ab74b1c53e1808ad16 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Sat, 1 Oct 2022 22:55:06 +0200 Subject: [PATCH] Extract referenced slf4j bundle for Maven runtime classpath again This is necessary because even the slf4j-bundle from Maven-Central is jar-singed as part of the m2e build when the m2e-repo is assembled. If the slf4j-jar is not extracted launching the embedded maven-runtime will fail with errors like: ``` class "org.slf4j.MavenSlf4jFriend"'s signer information does not match signer information of other classes in the same package ``` The reason for such an error is that the 'slf4j-api' jar and the 'maven-slf4j-provider' jar both provide classes for the package 'org.slf4j'. But all jars that provide classes for the same package must have the same jar-signer. And while the 'slf4j-api' jar is referenced as bundle and therefore signed in the m2e build (although it is originated from Maven-Central), the 'maven-slf4j-provider' jar embedded into the m2e.maven.runtime is not jar signed (because nested jars are not signed). Extracting the jar and providing them from a directory This check is not performed if a jar is extracted and added to the classpath as directory. Therefore only the slf4j jar is extracted again. Effectively this reverts commit 143c182b788e0f5e37dc36c63b24a13d2279ccc0 for slf4j. Additionally this ensures that paths to jars are canonicalized. --- .../eclipse/m2e/core/internal/Bundles.java | 29 ++++++++++--------- .../internal/launch/MavenEmbeddedRuntime.java | 13 +++++---- .../m2e/internal/launch/MavenLaunchUtils.java | 2 +- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Bundles.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Bundles.java index 93dfd14ba..b8d490b69 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Bundles.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Bundles.java @@ -44,7 +44,7 @@ private Bundles() { private static final Logger log = LoggerFactory.getLogger(Bundles.class); - public static List getClasspathEntries(Bundle bundle) { + public static List getClasspathEntries(Bundle bundle, boolean extractJar) { log.debug("getClasspathEntries(Bundle={})", bundle); Set cp = new LinkedHashSet<>(); if(inDevelopmentMode()) { @@ -53,13 +53,7 @@ public static List getClasspathEntries(Bundle bundle) { cp.addAll(parseBundleClasspath(bundle)); List entries = new ArrayList<>(); for(String cpe : cp) { - String entry; - if(".".equals(cpe)) { - entry = FileLocator.getBundleFileLocation(bundle) - .orElseThrow(() -> new NoSuchElementException("Unable to locate bundle:" + bundle)).toString(); - } else { - entry = getClasspathEntryPath(bundle, cpe); - } + String entry = getClasspathEntryPath(bundle, cpe, extractJar); if(entry != null) { log.debug("\tEntry:{}", entry); entries.add(entry); @@ -81,16 +75,23 @@ private static List parseBundleClasspath(Bundle bundle) { return List.of("."); } - public static String getClasspathEntryPath(Bundle bundle, String cp) { + public static String getClasspathEntryPath(Bundle bundle, String cp, boolean extractJar) { // try embedded entries first - URL url = bundle.getEntry(cp); - if(url != null) { - try { + try { + if(".".equals(cp)) { + if(!extractJar) { + return FileLocator.getBundleFileLocation(bundle) + .orElseThrow(() -> new NoSuchElementException("Unable to locate bundle:" + bundle)).getCanonicalPath(); + } + cp = "/"; // get bundle's root entry below, which extracts the bundle's jar, if it not of shape 'dir' already + } + URL url = bundle.getEntry(cp); + if(url != null) { String path = FileLocator.toFileURL(url).getFile(); return new Path(path).toOSString(); - } catch(IOException ex) { - log.warn("Could not get entry {} for bundle {}", cp, bundle, ex); } + } catch(IOException ex) { + log.warn("Could not get entry {} for bundle {}", cp, bundle, ex); } // in development mode entries can be absolute paths outside of bundle basedir diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/launch/MavenEmbeddedRuntime.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/launch/MavenEmbeddedRuntime.java index 28556de6a..c23ed8f8c 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/launch/MavenEmbeddedRuntime.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/launch/MavenEmbeddedRuntime.java @@ -112,6 +112,8 @@ public void createLauncherConfiguration(IMavenLauncherConfiguration collector, I } } + public static final Set SLF4J_BUNDLE_NAMES = Set.of("org.slf4j.api", "slf4j.api"); + private synchronized void initClasspath() { if(CLASSPATH == null) { Bundle mavenRuntimeBundle = findMavenEmbedderBundle(); @@ -120,9 +122,8 @@ private synchronized void initClasspath() { addBundleClasspathEntries(allEntries, mavenRuntimeBundle, true); allEntries.add(getEmbeddedSLF4JBinding(mavenRuntimeBundle)); - Set noDependencyBundles = Set.of("org.slf4j.api", "slf4j.api"); // Don't include dependencies of slf4j bundle to ensure no other than the slf4j-binding embedded into m2e.maven.runtime is available. - Set bundles = getRequiredBundles(mavenRuntimeBundle, noDependencyBundles); + Set bundles = getRequiredBundles(mavenRuntimeBundle, SLF4J_BUNDLE_NAMES); for(Bundle bundle : bundles) { addBundleClasspathEntries(allEntries, bundle, false); @@ -141,11 +142,13 @@ private synchronized void initClasspath() { } private void addBundleClasspathEntries(Set entries, Bundle bundle, boolean addFragments) { - entries.addAll(Bundles.getClasspathEntries(bundle)); + boolean extractRoot = SLF4J_BUNDLE_NAMES.contains(bundle.getSymbolicName()); + // Use extracted/directory form of slf4j bundles so that their jar-signing signature by the Maven-runtime classloader + entries.addAll(Bundles.getClasspathEntries(bundle, extractRoot)); Bundle[] fragments; if(addFragments && (fragments = Platform.getFragments(bundle)) != null) { for(Bundle fragment : fragments) { - entries.addAll(Bundles.getClasspathEntries(fragment)); + entries.addAll(Bundles.getClasspathEntries(fragment, SLF4J_BUNDLE_NAMES.contains(fragment.getSymbolicName()))); } } } @@ -154,7 +157,7 @@ private static String getEmbeddedSLF4JBinding(Bundle mavenBundle) { String bindingPath = mavenBundle.getHeaders().get(M2E_SL4J_BINDING_HEADER); Objects.requireNonNull(bindingPath, () -> "Missing '" + M2E_SL4J_BINDING_HEADER + "' header in embedded Maven-runtime bundle"); - String bindingJarPath = Bundles.getClasspathEntryPath(mavenBundle, bindingPath); + String bindingJarPath = Bundles.getClasspathEntryPath(mavenBundle, bindingPath, false); return Objects.requireNonNull(bindingJarPath, () -> M2E_SL4J_BINDING_HEADER + " '" + bindingPath + "' not found"); } diff --git a/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchUtils.java b/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchUtils.java index 9ce4b127c..d2b9b195e 100644 --- a/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchUtils.java +++ b/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchUtils.java @@ -55,7 +55,7 @@ public static AbstractMavenRuntime getMavenRuntime(ILaunchConfiguration configur public static List getCliResolver(AbstractMavenRuntime runtime) { if(runtime.getVersion().startsWith("3.")) { //$NON-NLS-1$ Bundle m2eWorkspaceCLIBundle = FrameworkUtil.getBundle(WorkspaceState.class); - return Bundles.getClasspathEntries(m2eWorkspaceCLIBundle); + return Bundles.getClasspathEntries(m2eWorkspaceCLIBundle, false); } return Collections.emptyList(); // unsupported version of maven }