BackwardCompatibilityPatches

Revision as of 13:08, 8 April 2014 by Sdedic (Talk | contribs)

Contents

Backwards compatibility support

NetBeans contain deprecated obsolete code, which is typically left in place for several releases. In addition to add polution to the API, it also increases the number of dependencies to both ancient modules and Java platform. The deprecated code is a dead weight in the released NB product, as the shipped modules are (or should be) upgraded to work with API modules in their current versions, not using deprecated APIs.

The purpose of this backward compatible support is to preserve binary compatibility for unmaintained modules, or 3rd party modules with a different release cycle while allowing to remove obsolete code from the public APIs.

The following techniques can be used for backward compatibility:

Accessor method

A compatible implementation may need to access the internals possibly from a different module (classloader). @PatchedPublic annotation currently serves this purpose.

The annotated method is patched to be public at runtime, while the class is being loaded. The calling code is typically resides in the same package, although a different module with an implementation dependency. Using @PatchedPublic it can access the method even at runtime, although from a different classloader.

Note that this approach still requires that method signature dependencies affect the API module dependency closure. All types referenced from the signature must be present for the compilation and execution of the API module. If the referenced type contains an illegal platform or library dependency in its API/impl, then the illegal component infects even the API module.

Module Fragment

If a class in a module A patches a class in module B, the system must esnure proper visibility between A and B classloaders. With the Compatible Superclass approach, the compatibility class in A typically uses types defined by B, but B must see A's contents at run-time as B class will be made to extend A type (see below). The simplest way is to join contents of A and B in the same classloader.

If a module's MANIFEST.MF defines OpenIDE-Module-Fragment-Host: header, the module becomes a Module Fragment and its contents is included into the fragment host's module classloader.

Example

This is an example MANIFEST.MF of openide.filesystems module:

   Manifest-Version: 1.0
   OpenIDE-Module: org.openide.filesystems
   OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
   OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
   OpenIDE-Module-Specification-Version: 9.0


A compatibility support module, which needs to merge with filesystems API at runtime uses the following MANIFEST:

   Manifest-Version: 1.0
   OpenIDE-Module: org.openide.filesystems.compat8
   OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/compat8/Bundle.properties
   OpenIDE-Module-Specification-Version: 9.0
   OpenIDE-Module-Fragment-Host: org.openide.filesystems

There's no dependency from the real API module to the patch; the patch depends on the API module. The patch module may be eventually not present at all, if compatibility is not needed.

Compatible superclass

Because of JVM definition of method resolution, JVM looks not only in the class hosting the target method and specified as part of the Method Reference, but also in superclasses of that class. It's therefore binary-compatible to move the methods to some superclass.

We must still prevent the superclass from appearing in the `extends` clause of the source, in order not to retain the dependencies from the superclass' dependency closure (the requirement was to avoid them). At run-time, the API class A which was compiled as extending superclass S, will be patched to extend another superclass, C. Provided that C extends S, type checks in the running JVM should not be affected. The superclass C can then add methods with illegal dependencies in their transitive dependency closure.

The class which delivers the binary-compatible implementation must be annotated using @PatchFor annotation, which also identifies the target class which should be modified at run-time. To preserve inheritance hierarchy properties, there are some rules to be followed. Given API class "A" which extends "X", and binary-compatible implementation class "A"

  • I must also extend X
  • I must define the constructors with the same signature as X
  • A must contain a default constructor, implicit or explicit

In addition, A and I must be loaded by the same classloader. To instruct NetBeans module system to do so, the module that contain I must list the following Manifest entry: OpenIDE-Module-Fragment-Host: codename where the 'codename' identifies the original module which contains API class A.

Constructor delegate

API class A may have a constructor, which is no longer acceptable, because of its signature dependencies. If the constructor was just implemented in an 'unlucky' way, the implementation could be lobotomized, but if the constructor's signature contain an unwanted dependency, it should be rather removed at all from the class.

To preserve backward compatibility, the constructor has to be added back at run-time. Although JVM linking algorithm would eventually find <init>()V method to call after new, the constructor "inherited" from the superclass would not be able to initialize the API class fields.

The initialization of the original API class is implemented by its default constructor - this means the API class must have default constructor, even though it is private. Delegation to other A constructors is not implemented yet, but is feasible.

Initialization of the superclass, or possibly setup of API (A) fields are delegated to a static "factory" method in the @PatchFor superclass. The initialization method must be annotated with @ConstructorDelegate. It's first parameter must be of type of the compatible superclass itself and the rest of parameters must be the same as the to-be-generated constructor in the API class. Modifiers and declared exceptions are copied to the generated constructor.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo