Re: Annotation scanning with java 9 multi version jars

Greg Wilkins


I've had a conversations regarding this issue on jigsaw-dev and core-libs-dev. While there was some acknowledgement that the JarFile API is incomplete regarding support for Multi Release jars, there was not much enthusiasm taking on the responsibility of filtering out non applicable classes.

Specifically I proposed:
the stream needs to handle inner classes and only include them
if their matching outerclass is available at the same version. So for
example a base Foo$Bar.class will only be included if the stream includes a
base Foo.class, and it will not be included if the Foo.class is version 9
or above. Likewise a version 9 Foo$Bar.class will only be included in the
stream if the stream also includes a version 9 Foo.class, and will not be
included if the stream has a version 10 or above Foo.class

and provided a proposed implementation: 

to which the response from Alan Bateman at oracle was:

I don't think this should be pushed down to the JarFile API. The JarFile
API provides the base API for accessing JAR files and should not be
concerned with the semantics or relationship between entries. I agree
that annotation scanning tools and libraries need to do additional work
to deal with orphaned or menacing inner classes in a MR JAR but it's not
too different to arranging a class path with a JAR file containing the
"classes for JDK 9" ahead of a JAR file containing the version of the
library that runs on JDK 8. I do think that further checks could be done
by the `jar` tool to identify issues at packaging time.

So if that view prevails, then it is up to the application specification and container developers to agree on a semantic of what classes will be scanned, else we will have a major portability problem.   There were several responses in the discussion there that indicated that such problems are already being seen in the wild as libraries are being released using this features in advance of the tools being able to cope.

So it would be really great if we could come up with an agreement on how to apply interpret the "semantic relationships" within a MR Jar.      

I think the main driver for my proposal are that: it avoids the need to analyse the class files to determine relationships and applicability; b) it is a likely default layout for MR jars;  c) it has defensible semantics.

However, I think it more important that there is an agreed portable interpretation, rather than any one interpretation, so happy to consider other proposals.


On 14 September 2017 at 03:28, Mark Thomas <markt@...> wrote:
On 13/09/2017 01:02, Greg Wilkins wrote:
> All,
> We are a bit concerned with providing reasonable support for annotation
> scanning in java 9 multi version jars.


> We are already seeing these jars in our java 8 deployments (from some
> logging frameworks), so we are having to update our scanning to ignore
> the versioned classes (as they can't be java 8).
> However, we want to update our scanning to support running on java 9,
> but just cannot work out a good algorithm for doing so, specially when
> confronted with inner classes.
> A multi versioned jar might contain something like:
>   * org/example/Foo.class
>   * org/example/Foo$Bar.class
>   * META-INF/versions/9/org/example/Foo.class
> So it is clear that there is a java 9 version of Foo.  But what is
> unclear is the inner class Foo$Bar?  Is that only used by the base Foo
> version? or does the java 9 version also use the Foo$Bar inner class,
> but it didn't use any java 9 features, so the base version is able to be
> used??
> So it looks like we are going to need to analyse the actual Foo class
> version used to see if Foo$Bar is referenced and only then scan Foo$Bar
> for annotations (and recursive analysis for Foo$Bar$Bob class )!     It
> means that given the index only of a jar, it is impossible to come up
> with the list of classes that will be provided by that jar for a given
> JVM!    The only alternative would be if there was an enforced
> convention that any versioned class would also version all of it's inner
> classes - which may be a reasonable assumption given that they would be
> compiled together, but we see nothing in the specifications that force a
> jar to be assembled that way.
> Is this something the other containers are assuming (ie if there is  no
> META-INF/versions/9/org/example/Foo$Bar.class, then the inner class is
> not used by the versioned outer class and thus do not scan
> org/example/Foo$Bar.class)?
> Or are we going to have to engage in code analysis just to determine
> which classes we need to analyse for annotations?

We (Tomcat) haven't had any reports of problems in this area yet. It is
on the list of things to worry about (and thanks for setting out the
problems so clearly) but we haven't looked at a solution yet.

The convention that any versioned class would also version all of it's
inner classes sounds like a reasonable solution to me.

Have you asked about this on jigsaw-dev@... ?



Greg Wilkins <gregw@...> CTO

Join to automatically receive all group messages.