diff --git a/tycho-its/projects/eeProfile.java25/bundle/META-INF/MANIFEST.MF b/tycho-its/projects/eeProfile.java25/bundle/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..fed5129671 --- /dev/null +++ b/tycho-its/projects/eeProfile.java25/bundle/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Bundle +Bundle-SymbolicName: java25.bundle +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-25 diff --git a/tycho-its/projects/eeProfile.java25/bundle/build.properties b/tycho-its/projects/eeProfile.java25/bundle/build.properties new file mode 100644 index 0000000000..5f22cdd448 --- /dev/null +++ b/tycho-its/projects/eeProfile.java25/bundle/build.properties @@ -0,0 +1 @@ +bin.includes = META-INF/ diff --git a/tycho-its/projects/eeProfile.java25/bundle/pom.xml b/tycho-its/projects/eeProfile.java25/bundle/pom.xml new file mode 100644 index 0000000000..0dc2658903 --- /dev/null +++ b/tycho-its/projects/eeProfile.java25/bundle/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + + tycho-its-project.eeProfile.java25 + 1.0.0-SNAPSHOT + parent + + + java25.bundle + eclipse-plugin + + diff --git a/tycho-its/projects/eeProfile.java25/pom.xml b/tycho-its/projects/eeProfile.java25/pom.xml new file mode 100644 index 0000000000..e22e33d1d7 --- /dev/null +++ b/tycho-its/projects/eeProfile.java25/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + tycho-its-project.eeProfile.java25 + 1.0.0-SNAPSHOT + parent + pom + + + bundle + + + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho-version} + true + + + org.eclipse.tycho + tycho-compiler-plugin + ${tycho-version} + + javac + + + + + diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/eeProfile/Java25ResolutionTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/eeProfile/Java25ResolutionTest.java new file mode 100644 index 0000000000..3af6dd3617 --- /dev/null +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/eeProfile/Java25ResolutionTest.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2025 Contributors and others. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Contributors - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.test.eeProfile; + +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.apache.maven.it.Verifier; +import org.eclipse.tycho.test.AbstractTychoIntegrationTest; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore("unless java 25 jvm is available to tycho build") +public class Java25ResolutionTest extends AbstractTychoIntegrationTest { + + @Test + public void testBundleBuildForJava25() throws Exception { + // Test that a bundle with JavaSE-25 BREE can be built with javac compiler + Verifier verifier = getVerifier("eeProfile.java25", false); + verifier.executeGoal("verify"); + verifier.verifyErrorFreeLog(); + verifier.verifyTextInLog("Building jar:"); + File buildResult = new File(verifier.getBasedir()); + File bundleJar = new File(buildResult, "bundle/target/java25.bundle-1.0.0-SNAPSHOT.jar"); + assertTrue("Bundle JAR should exist", bundleJar.exists()); + } + +} diff --git a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/BndManifestProcessor.java b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/BndManifestProcessor.java index a95778a730..de3015e0c7 100644 --- a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/BndManifestProcessor.java +++ b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/BndManifestProcessor.java @@ -131,6 +131,23 @@ private void enhanceReqCap(Attributes mainAttributes, Attributes calcAttributes) String existingValue = mainAttributes.getValue(Constants.REQUIRE_CAPABILITY); String newValue = calcAttributes.getValue(Constants.REQUIRE_CAPABILITY); if (newValue != null) { + // Fix for JavaSE-25 and future Java versions not recognized by bndlib + // Bnd's Analyzer may generate osgi.ee=UNKNOWN for unrecognized BREE values + // We need to detect and fix this before it gets into the manifest + // See https://github.com/bndtools/bnd/issues/6858 + if (newValue.contains("UNKNOWN")) { + String breeHeader = mainAttributes.getValue(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); + if (breeHeader != null && !breeHeader.isEmpty()) { + String fixedFilter = convertBreeToOsgiEeFilter(breeHeader); + if (fixedFilter != null) { + // Replace the UNKNOWN filter with the correct one + newValue = newValue.replaceAll("osgi\\.ee;\\s*filter:=\"[^\"]*UNKNOWN[^\"]*\"", + "osgi.ee;filter:=\"" + fixedFilter + "\""); + logger.debug("Fixed UNKNOWN osgi.ee filter to: " + fixedFilter); + } + } + } + Parameters additional = OSGiHeader.parseHeader(newValue); if (additional.containsKey(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE)) { // remove deprecated header but use the ee namespace @@ -164,4 +181,47 @@ private void enhanceReqCap(Attributes mainAttributes, Attributes calcAttributes) } } + /** + * Converts a Bundle-RequiredExecutionEnvironment (BREE) value to an osgi.ee filter. + * This is a workaround for bndlib not recognizing newer Java versions (like JavaSE-25). + * + * @param breeHeader the BREE header value (e.g., "JavaSE-25" or "JavaSE-17,JavaSE-25") + * @return an osgi.ee filter string, or null if the BREE cannot be parsed + */ + private String convertBreeToOsgiEeFilter(String breeHeader) { + // BREE can contain multiple comma-separated values, we need to pick the highest version + String[] brees = breeHeader.split(","); + int highestVersion = -1; + + for (String bree : brees) { + bree = bree.trim(); + // Parse JavaSE-XX or J2SE-XX format + if (bree.startsWith("JavaSE-") || bree.startsWith("J2SE-")) { + try { + String prefix = bree.startsWith("JavaSE-") ? "JavaSE-" : "J2SE-"; + String versionStr = bree.substring(prefix.length()); + // Remove "1." prefix if present (e.g., "1.8" -> "8") + if (versionStr.startsWith("1.")) { + versionStr = versionStr.substring(2); + } + int version = Integer.parseInt(versionStr); + if (version > highestVersion) { + highestVersion = version; + } + } catch (NumberFormatException e) { + // Ignore malformed BREE entries + } + } + } + + if (highestVersion > 0) { + // Convert to osgi.ee filter format: (&(osgi.ee=JavaSE)(version=XX)) + // Note: J2SE is mapped to JavaSE for the filter + return "(&(osgi.ee=JavaSE)(version=" + highestVersion + "))"; + } + + return null; + } + } +