Hi Gregg,
The metadata represents package and class api signatures, it's a
property of the code that already exists, that we capture. We can then
make the information available without needing to load a class file
first. Because Java doesn't allow reloading of class files in the same
classloader, well not yet at least, I'd like to verify that the class
being loaded is compatible prior to loading.
Once you identify a packages API, it makes sense to catalogue it against
a version number of some sort, OSGi already supports versioning metadata
so it seemed logical to use that convention. There are some language
changes in Java 7 to support modules, jsr 294 from memory I think.
Thanks,
Peter.
Gregg Wonderly wrote:
Is this meta data something we want to extract, or is it something
that we want developers to designate existence of either through
annotations or some other visible meta information?
Gregg Wonderly
Peter Firmstone wrote:
Dennis Reedy wrote:
So if this information is produced at build time, added into a jar's
manifest, what is the difference with using a convention of
something like a maven artifact to provide version and update support?
A very brief statement is that it would describe the actual API of a
package; the methods and fields of public class files, this
information would be generated from the classpath, without programmer
input, and stored as files in the jar file, in addition to the
current bundle metadata, see below:
I haven't worked out how to represent the metadata in textual form
yet, perhaps xml? The tool, uses a number of options to define its
analysis / search scope and classpath from which it builds a
collection containing DependencyRelationship objects that contain
class metadata. Each DependencyRelationship object contains two
collections, one for dependants and one for providers, each
DependencyRelationship forms a node in the dependency graph.
The DependencyRelationship objects can then grouped into a
collections, one for each package. You then iterate over the
collection to get all Provider's that are external to the package.
These DependencyRelationship Objects each represent a class from an
external (imported) package. This can then be grouped into
collections from different packages. Each of these collections
represent a dependency on an imported package.
The Package API itself is determined by class visibility. When I
refer to classes here, I'm referring to class files, so this
includes interfaces and abstract classes.
Only Public Classes form represent the Package API, from there you
drill down to the public class details:
* all public methods and field signatures.
* all protected method and field signatures.
* serialVersionUID
The DependencyPackageAPI signatures can be checked against the
PackageAPI signatures.
I guess this could be done with a method such as
public interface PackageMirror {
public boolean satisfies(DependencyPackageAPI depends);
}
The devils in the implementation details of the above method.
The devil is set out in Chapter 13 Binary Compatibility from the
Java Language Specification 3.0
Where this analysis gets really interesting is when a dependency is
published in return values of an exported PackageAPI, in this case a
client bundle importing a package from this bundle will also have to
import a Package that satisfies the common dependency. The runtime
will need to resolve all package dependencies prior to loading.
To generate the metadata I might persist to xml, all the
DependencyRelationship objects for a bundles exported packages as
well as the subset DepenencyRelationship objects from the import
package requirements.
The metadata might be stored in three files in the jar:
depends.xml
provides.xml
client_requirements.xml - packages that use this package X will
depend on these other packages, Y and Z, full PackageAPI signatures
must be captured for Y and Z also.
Or to be consistent with OSGi:
imports.xml
exports.xml
client_requirements.xml
If the metadata is too large (though I think they'll be ok) a SHA-1
checksum of these files might suffice, so they could be looked up as
required.
Currently my implementation only has the dependency relationships,
it doesn't yet harvest all the method and field signatures, although
this is quite straight forward with ASM.
As a result, a typical implentation will only depend upon the
interface, not package private classes or implementation details. A
later version of a Package could change a public class to a public
interface, and reimplement all methods in several package private
classes without altering the dependency metadata and still satisfy
backward compatibility. Just a quick question, does this "Package
API" differentiate between a bundle simply using an interface vs one
that implements it? Just wondering.
Yes, very much so, see above; one that simply uses it would not
publish it in its client requirements, however one that implements
it will.