bnd icon indicating copy to clipboard operation
bnd copied to clipboard

OSGi Java 9 support: Multi-release JAR

Open njbartlett opened this issue 8 years ago • 56 comments

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

njbartlett avatar Dec 06 '17 22:12 njbartlett

See also https://issues.apache.org/jira/browse/FELIX-5527

njbartlett avatar Dec 06 '17 22:12 njbartlett

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.

bjhargrave avatar Dec 06 '17 22:12 bjhargrave

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.

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

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?

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

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.

njbartlett avatar Dec 06 '17 23:12 njbartlett

You can have module-info.class under META-INF/versions. So you could have entirely different dependencies for Java 9, 10, etc.

njbartlett avatar Dec 06 '17 23:12 njbartlett

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.

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

Okay nice idea with Bundle-ClassPath.

njbartlett avatar Dec 06 '17 23:12 njbartlett

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)

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

The problem with the bundle classpath is that it needs to be conditional. So you would need an entry for each existing java version.

karlpauls avatar Dec 06 '17 23:12 karlpauls

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.

njbartlett avatar Dec 06 '17 23:12 njbartlett

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.

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

No. There will be multiple fragments which only resolve for the specific java version.

But they need to override each other.

karlpauls avatar Dec 06 '17 23:12 karlpauls

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?

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

But they need to override each other.

No. At most one of the fragments is attached and it supplies classes in the versioned folder.

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

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?

karlpauls avatar Dec 06 '17 23:12 karlpauls

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)

rotty3000 avatar Dec 06 '17 23:12 rotty3000

the thing is you can have:

/A.class /9/B.class /10/C.class /11/B.class

karlpauls avatar Dec 06 '17 23:12 karlpauls

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?

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

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

karlpauls avatar Dec 06 '17 23:12 karlpauls

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)?

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

At least that is what I think http://openjdk.java.net/jeps/238 is saying

karlpauls avatar Dec 06 '17 23:12 karlpauls

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.

karlpauls avatar Dec 06 '17 23:12 karlpauls

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".

njbartlett avatar Dec 06 '17 23:12 njbartlett

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.

karlpauls avatar Dec 06 '17 23:12 karlpauls

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.

karlpauls avatar Dec 06 '17 23:12 karlpauls

Bundle-Classpath: META-INF/versions/10,META-INF/versions/9,.

and then what you just proposed as layout.

karlpauls avatar Dec 06 '17 23:12 karlpauls

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.

bjhargrave avatar Dec 06 '17 23:12 bjhargrave

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 :-)

karlpauls avatar Dec 06 '17 23:12 karlpauls

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.

njbartlett avatar Dec 06 '17 23:12 njbartlett