OSGi Java 9 support: Multi-release JAR
This issue was raised against Felix (maven-bundle-plugin) but it needs to be addressed in bnd: https://issues.apache.org/jira/browse/FELIX-5592
See also https://issues.apache.org/jira/browse/FELIX-5527
Some more detail on what "support" for multi release jars would look like in OSGi is needed here.
Bnd could certain stop objecting to classes in META-INF/versions/9 but that would not make them available at runtime IF the runtime is Java 9.
This topic was discussed in a recent OSGi expert group call and the OSGi "way" here would be to use a fragment to supply the types for a java version with the host bundle carving out a space in the Bundle-Classpath.
But if Bnd is being fed a target/classes folder with classes in META-INF/versions/9, I am not sure how Bnd can make a bundle which will work as expected for multi release jars.
Also, if classes in META-INF/versions/9 exist, should Bnd process them for imports? The imports for the bundle may vary depending upon whether the classes in META-INF/versions/9 are "in effect". And there is no way to have imports conditional on the version of Java at runtime. This is why fragments to supply these types is more appropriate in OSGi since the fragments can supply additional imports (and exports) for the types.
How do JPMS modules and multi-release jars interact? I assume they are mutually exclusive since JPMS modules would have the same issues with varying requires/exports depending upon the runtime version of Java. Yes, this is not a practical issue yet for JPMS since it is only Java 9 for now. But with Java 10, then what?
Unfortunately the version-specific part under META-INF/versions can override the non-version-specific classes. It seems that a multi-release JAR would have to result in at least a base bundle plus one fragment for Java 9 and a further fragment for the pre-Java-9 code. We might be able to optimise this if we detect that there is actually no overlap.
You can have module-info.class under META-INF/versions. So you could have entirely different dependencies for Java 9, 10, etc.
We don't need a fragment for pre-Java 9 code. The host bundle would have all the pre-9 code and Bundle-Classpath: versioned, . and the fragment would have all its code in the versioned folder.
Okay nice idea with Bundle-ClassPath.
You can have module-info.class under META-INF/versions. So you could have entirely different dependencies for Java 9, 10, etc.
Hmm, so bnd could put different manifests under META-INF/versions and the framework would pick a manifest at runtime? (sigh)
META-INF/MANIFEST.MF (java 8 manifest)
META-INF/versions/9/META-INF/MANIFEST.MF (java 9 manifest)
The problem with the bundle classpath is that it needs to be conditional. So you would need an entry for each existing java version.
Yes I think that might need to be the way forward... runtime support for fragments nested inside a bundle. That way projects like log4j can just release a single JAR, which is what they want to do.
The problem with the bundle classpath is that it needs to be conditional. So you would need an entry for each existing java version.
No. There will be multiple fragments which only resolve for the specific java version.
No. There will be multiple fragments which only resolve for the specific java version.
But they need to override each other.
Yes I think that might need to be the way forward... runtime support for fragments nested inside a bundle. That way projects like log4j can just release a single JAR, which is what they want to do.
I think there are many issues here. Like how does Bundle.getEntry/getEntries treat this?
But they need to override each other.
No. At most one of the fragments is attached and it supplies classes in the versioned folder.
No. At most one of the fragments is attached and it supplies classes in the versioned folder.
So you would duplicate all classes from the other versions that are not overriden in this version in each fragment in the chain?
Could we add some new "effective"-ness' which map to Java version X?
Import-Package:
com.foo,
com.bar;effective=resolve-java9
Plus the Bundle-ClassPath?
On Wed, Dec 6, 2017 at 6:09 PM, BJ Hargrave [email protected] wrote:
You can have module-info.class under META-INF/versions. So you could have entirely different dependencies for Java 9, 10, etc.
Hmm, so bnd could put different manifests under META-INF/versions and the framework would pick a manifest at runtime? (sigh)
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bndtools/bnd/issues/2227#issuecomment-349805690, or mute the thread https://github.com/notifications/unsubscribe-auth/AAI9TKR4CisE1GdlTDIRmODvyhf5jsqbks5s9x6ngaJpZM4Q4tuA .
-- Raymond Augé http://www.liferay.com/web/raymond.auge/profile (@rotty3000) Senior Software Architect Liferay, Inc. http://www.liferay.com (@Liferay) Board Member & EEG Co-Chair, OSGi Alliance http://osgi.org (@OSGiAlliance)
the thing is you can have:
/A.class /9/B.class /10/C.class /11/B.class
So you would duplicate all classes from the other versions that are not overriden in this version in each fragment in the chain?
Why would you need to do that? Does multi release jars stack up all the versions? So that on Java 11, you search 11, then 10, then 9, then the base jar for a class?
Why would you need to do that? Does multi release jars stack up all the versions? So that on Java 11, you search 11, then 10, then 9, then the base jar for a class?
Yes
Yes
That is in insane design. Good luck building such a jar and keeping it operational in all the versions of java...
And how do you build all the module-infos for all these versions of java (if you use JPMS)?
At least that is what I think http://openjdk.java.net/jeps/238 is saying
In the example above, when running on an MRJAR-aware Java 9 JDK, it would see the 9-specific versions of A and B and the general versions of C and D; on a future MRJAR-aware Java 10 JDK, it would see the 10-specific version of A and the 9-specific version of B;
So i would say yes, they stack.
I think the structure would look like this:
A.class (pre-Java 9 class)
B.class (pre-Java 9 class)
META-INF/
\- MANIFEST.MF:
Bundle-SymbolicName: foo
Bundle-ClassPath: versioned, .
Require-Capability: osgi.ee; filter:='(osgi.ee=JavaSE-1.8)'
\- versions
\- 9
\- A.class (java 9 class)
B.class (java 9 class)
META-INF/MANIFEST.MF:
Fragment-Host: foo
Require-Capability: osgi.ee; filter:='(osgi.ee=JavaSE-9)'
\- 10
\- A.class (java 10 class)
B.class (java 10 class)
META-INF/MANIFEST.MF:
Fragment-Host: foo
Require-Capability: osgi.ee; filter:='(osgi.ee=JavaSE-10)'
A smaller problem is that the fragment for Java 9 would resolve on Java 10 because EEs include every previous EE. We would have to express a dependency on the EE of "exactly Java 9".
Part of me wonders if the solution is to really make them fragments inside the bundle. I.e., if a dir on the bundle-classpath has a META-INF/MANIFEST.mf we should just handle it like a fragment.
A smaller problem is that the fragment for Java 9 would resolve on Java 10 because EEs include every previous EE. We would have to express a dependency on the EE of "exactly Java 9".
No, I think we want exactely that.
Bundle-Classpath: META-INF/versions/10,META-INF/versions/9,.
and then what you just proposed as layout.
I think we need to stop fixing this in this bug. This is sounding more than Bnd can address alone. Changes are need in the Core spec to address this. And then Bnd can support the Core changes.
I think we need to stop fixing this in this bug. This is sounding more than Bnd can address. Changes are need in the Core spec to address this. And then Bnd can support the Core changes.
This is what I told David last week and what made him bring it up in your call (and because I had the feeling that wasn't the conclusion of the call I pinged Neil about it today :-)
Bundle-Classpath: META-INF/10,META-INF/9,.
Yes I think this works, and bnd can generate that. It becomes tricky when the user wants to use Bundle-ClassPath for something else as well, but maybe that should just be disallowed.
Agree with BJ that bnd should follow CPEG.