From a5524529d6013cbbd02327df50c6a08af9e313be Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Mon, 9 Oct 2023 17:13:04 +0200 Subject: [PATCH 1/2] Cleans up the module names according to JPMS rules. --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- .../src/aQute/bnd/osgi/JPMSModule.java | 19 +++++++++++++++++++ .../bnd/plugin/jpms/JPMSModuleInfoPlugin.java | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java index 545321b02a..b0f9628d66 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java @@ -11,6 +11,8 @@ import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import aQute.bnd.build.model.EE; import aQute.bnd.classfile.ModuleAttribute; @@ -490,4 +492,21 @@ public int getNextRelease(int release) { return tailSet.first(); } + /** + * Cleanup a bsn so that it matches a JPMS module name + * + * @param bsn a symbolic name or null + * @return a name that matches the JPMS specification for a module name or + * null if the input was null + */ + public static String cleanupName(String bsn) { + if (bsn == null) + return null; + + String[] split = bsn.split("[^A-Za-z0-9]+"); + return Stream.of(split) + .filter(str -> !str.isEmpty()) + .collect(Collectors.joining(".")); + } + } diff --git a/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java b/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java index 997b7f9400..795749838e 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java +++ b/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java @@ -242,13 +242,14 @@ private String getModuleName(Analyzer analyzer, JPMSModule m, Parameters moduleI if (logger.isDebugEnabled()) logger.debug("Using module name '{}' for: {}", moduleName, jar); } - return moduleName; + return JPMSModule.cleanupName(moduleName); } private String name(Analyzer analyzer) { - return analyzer.getProperty(AUTOMATIC_MODULE_NAME, analyzer.getBsn()); + return analyzer.getProperty(AUTOMATIC_MODULE_NAME, JPMSModule.cleanupName(analyzer.getBsn())); } + private void packages(ModuleInfoBuilder builder, Analyzer analyzer) { MapStream.ofNullable(analyzer.getJar() .getDirectories()) From e30400fce9432ce5ea8446c0bf2658854fb8cb18 Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Tue, 10 Oct 2023 09:37:29 +0200 Subject: [PATCH 2/2] There were test consequences. --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- .../test/jpms/JPMSModuleInfoPluginTest.java | 38 +++++++++---------- .../src/aQute/bnd/osgi/JPMSModule.java | 8 ++++ .../bnd/plugin/jpms/JPMSModuleInfoPlugin.java | 11 ++---- .../test/aQute/bnd/osgi/JPMSModuleTest.java | 29 ++++++++++++++ 4 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 biz.aQute.bndlib/test/aQute/bnd/osgi/JPMSModuleTest.java diff --git a/biz.aQute.bndlib.tests/test/test/jpms/JPMSModuleInfoPluginTest.java b/biz.aQute.bndlib.tests/test/test/jpms/JPMSModuleInfoPluginTest.java index d5ab43ea08..7e9ac2184a 100644 --- a/biz.aQute.bndlib.tests/test/test/jpms/JPMSModuleInfoPluginTest.java +++ b/biz.aQute.bndlib.tests/test/test/jpms/JPMSModuleInfoPluginTest.java @@ -157,7 +157,7 @@ public void moduleWithOptionsIgnore() throws Exception { assertThat(moduleAttribute.requires).hasSize(3) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")); ModulePackagesAttribute modulePackagesAttribute = Arrays.stream(module_info.attributes) @@ -212,7 +212,7 @@ public void moduleWithOptionsStatic() throws Exception { assertThat(moduleAttribute.requires).hasSize(4) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -395,7 +395,7 @@ public void moduleWithAllDynamicImportsOrOptionalIsStatic() throws Exception { assertThat(moduleAttribute.requires).hasSize(4) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -403,7 +403,7 @@ public void moduleWithAllDynamicImportsOrOptionalIsStatic() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_STATIC_PHASE); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -459,7 +459,7 @@ public void moduleWithAllDynamicImportsIsStatic_2() throws Exception { assertThat(moduleAttribute.requires).hasSize(4) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -467,7 +467,7 @@ public void moduleWithAllDynamicImportsIsStatic_2() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_STATIC_PHASE); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -524,7 +524,7 @@ public void moduleWithAllDynamicImportsIsStatic() throws Exception { assertThat(moduleAttribute.requires).hasSize(4) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -532,7 +532,7 @@ public void moduleWithAllDynamicImportsIsStatic() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_STATIC_PHASE); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -588,7 +588,7 @@ public void moduleWithAllResolutionOptionalImportsIsStatic() throws Exception { assertThat(moduleAttribute.requires).hasSize(4) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -596,7 +596,7 @@ public void moduleWithAllResolutionOptionalImportsIsStatic() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_STATIC_PHASE); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -652,7 +652,7 @@ public void moduleWithNoImportsIsStatic() throws Exception { assertThat(moduleAttribute.requires).hasSize(5) .anyMatch(e -> e.requires.equals("java.base")) .anyMatch(e -> e.requires.equals("java.management")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -660,7 +660,7 @@ public void moduleWithNoImportsIsStatic() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_STATIC_PHASE); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -716,7 +716,7 @@ public void moduleManualConfiguration() throws Exception { assertThat(moduleAttribute.requires).hasSize(5) .anyMatch(e -> e.requires.equals("bar")) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -728,7 +728,7 @@ public void moduleManualConfiguration() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(0); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -793,7 +793,7 @@ public void moduleRequiresModuleB() throws Exception { assertThat(moduleAttribute.requires).hasSize(4) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")) .anyMatch(e -> e.requires.equals("java.json.bind")); @@ -805,7 +805,7 @@ public void moduleRequiresModuleB() throws Exception { .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(0); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); @@ -869,7 +869,7 @@ public void moduleRequiresModuleA() throws Exception { assertThat(moduleAttribute.requires).hasSize(3) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .anyMatch(e -> e.requires.equals("java.json")); assertThat(moduleAttribute.uses).hasSize(0); @@ -931,9 +931,9 @@ public void moduleRequiresA() throws Exception { assertThat(moduleAttribute.requires).hasSize(2) .anyMatch(e -> e.requires.equals("java.base")) - .anyMatch(e -> e.requires.equals("geronimo-jcdi_2.0_spec")); + .anyMatch(e -> e.requires.equals("geronimo.jcdi.2.0.spec")); - assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo-jcdi_2.0_spec")) + assertThat(moduleAttribute.requires).filteredOn(e -> e.requires.equals("geronimo.jcdi.2.0.spec")) .flatExtracting(e -> Arrays.asList(e.requires_flags)) .containsExactlyInAnyOrder(ModuleAttribute.Require.ACC_TRANSITIVE); diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java index b0f9628d66..5a4a601cd6 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/JPMSModule.java @@ -502,6 +502,14 @@ public int getNextRelease(int release) { public static String cleanupName(String bsn) { if (bsn == null) return null; + if ( bsn.endsWith(".jar")) + bsn= bsn.substring(0, bsn.length()-4); + + Pattern STRIP_SUFFIX_P = Pattern.compile("-\\d+\\..*$"); + Matcher m = STRIP_SUFFIX_P.matcher(bsn); + if (m.find()) { + bsn = bsn.substring(0, m.start()); + } String[] split = bsn.split("[^A-Za-z0-9]+"); return Stream.of(split) diff --git a/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java b/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java index 795749838e..adf4413abd 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java +++ b/biz.aQute.bndlib/src/aQute/bnd/plugin/jpms/JPMSModuleInfoPlugin.java @@ -51,7 +51,6 @@ import java.util.Set; import java.util.function.Supplier; import java.util.jar.Manifest; -import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; @@ -227,14 +226,12 @@ private String getModuleName(Analyzer analyzer, JPMSModule m, Parameters moduleI return null; } - moduleName = jar.getName(); - Matcher matcher = mangledModuleName.matcher(moduleName); - if (matcher.matches()) { - moduleName = matcher.group(1); - } + moduleName = JPMSModule.cleanupName(jar.getName()); final String name = moduleName; moduleName = moduleInfoOptions.stream() - .filterValue(attrs -> name.equals(attrs.get(SUBSTITUTE_ATTRIBUTE))) + .mapValue(attrs -> attrs.get(SUBSTITUTE_ATTRIBUTE)) + .mapValue(JPMSModule::cleanupName) + .filterValue(s -> name.equals(s)) .keys() .findFirst() .orElse(moduleName); diff --git a/biz.aQute.bndlib/test/aQute/bnd/osgi/JPMSModuleTest.java b/biz.aQute.bndlib/test/aQute/bnd/osgi/JPMSModuleTest.java new file mode 100644 index 0000000000..4d0c7ff770 --- /dev/null +++ b/biz.aQute.bndlib/test/aQute/bnd/osgi/JPMSModuleTest.java @@ -0,0 +1,29 @@ +package aQute.bnd.osgi; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class JPMSModuleTest { + + @Test + void cleanupTest() { + assertThat(JPMSModule.cleanupName("foo-1.0.jar")).isEqualTo("foo"); + assertThat(JPMSModule.cleanupName("bar-foo.jar")).isEqualTo("bar.foo"); + assertThat(JPMSModule.cleanupName("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")) + .isEqualTo("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + assertThat(JPMSModule.cleanupName("foo.jar")).isEqualTo("foo"); + assertThat(JPMSModule.cleanupName("foo")).isEqualTo("foo"); + assertThat(JPMSModule.cleanupName("foo.bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("-foo.bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("-foo.bar-")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("-foo......................bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("foo.--.bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("-------------------------foo.--.bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("-------------------------foo.-🙂-.bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("foo🙂bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName("\n\nfoo🙂bar")).isEqualTo("foo.bar"); + assertThat(JPMSModule.cleanupName(null)).isNull(); + } + +}