Refactorability proposal...
Bryan Atsatt
bryan.atsatt at ORACLE.COM
Fri Jun 13 13:10:43 PDT 2008
Yes, this could be an issue. If JavaEE:4.0.0 merely imports and
re-exports the specific packages, the imports can just be copied out. If
it actually contains them, and they themselves declare their own
versions, the jam tool could emit imports for those specific versions,
but it cannot generate ranges.
This brings us back to the "contract" idea: a named/versioned collection
of import constraints. The indirection afforded by this could certainly
solve this problem.
And we do have it, sort of: a module that contains no classes or
resources itself, only imports and re-exports. In the current model,
this is a bit of a hack because the module will actually be instantiated
with its own loader, which is a waste of cycles/resources.
If, OTOH, we special case such "contract" ("indirect"?) modules such
that they are not instantiated (or at least don't have a loader) but act
only as a bag of import constraints that can be "borrowed" by an
importer, that seems like a reasonable solution.
This could be simplified by doing the borrowing at build time, as in my
proposal, at the cost of some loss of flexibility.
// Bryan
Adrian Brock wrote:
> Another issue would be how you handle the generated package
> constraints.
>
> e.g. Suppose you a module JavaEE:4.0.0 that
> contains packages javax.jms:1.1.0, javax.resource:1.5.0, etc.
>
> I then declare a module constraint
> JavaEE:[4.0.0, 5.0.0)
> i.e. I work with JavaEE4 but not JavaEE5
>
> What do the package constraints resolve to for jms and jca
> if we don't have a JavaEE5 module in the repository? :-)
>
> JavaEE is not a very a good example since package versions
> wouldn't change across a major release, but they could
> in other cases or more general module version constraints.
>
> On Tue, 2008-06-10 at 18:27 -0700, Bryan Atsatt wrote:
>
>> (FYI: I've discussed this with Stanley but wanted to ensure it was
>> visible to everyone.)
>>
>> Proposal
>>
>> 1. Eliminate runtime use of import-by-module in the JAM system:
>>
>> a. Support the (very convenient) import-by-module at the source level.
>> b. jam tool transforms import-by-module to a list of
>> import-by-package statements.
>>
>> 2. Add APIs to fully support import-by-package in the JAM system:
>>
>> a. Support Version annotation in package-info.java (or in
>> module-info.java). If a
>> package does not declare a version, it "inherits" that of the
>> enclosing module.
>> b. Add ImportPackage annotation with version constraints.
>>
>> 3. Add APIs to fully support import-by-package in the abstract framework:
>>
>> a. Add methods to Query to produce import-by-package nodes.
>> b. Replace Query.getIndexableNames() with fully generic variants (I
>> proposed
>> a solution here previously which I will re-post).
>>
>> Rationale
>>
>> Module refactoring is inevitable, particularly during the transition
>> from the current, effectively flat class space to a fine-grained space
>> provided by module systems. We have significant experience with this
>> issue at Oracle (with the transition to our own module system), and OSGi
>> best-practices for conversion include starting with everything in one
>> bundle and then separating out pieces as experience is gained.
>>
>> A very common pattern, in our experience, is for developers to start
>> with many extra jars in their initial module (a mini version of
>> class-path hell). As that module is put into wider use, someone
>> discovers that package X is also contained in their module, and that
>> duplication either leads to runtime conflicts (very bad), or just plain
>> footprint bloat. The obvious answer is to put package X in a separate
>> module, and have everyone share it via imports.
>>
>> But... not so fast. If there are consumers of that module who import it
>> by module name alone, then pulling X out of it will cause those
>> importers to break. And if it is possible for your module to have been
>> imported by *anyone* by name alone, then you are stuck: either you break
>> them or you live with the incorrect granularity (which just isn't an
>> option in the conflict scenarios). Not a happy choice.
>>
>> Originally, I had proposed to do away with import-by-module altogether,
>> both to avoid this problem and to eliminate the conceptual disconnect.
>> Your code does not today contain import statements that name *jars*, it
>> names packages and/or specific classes in those packages. Why invent a
>> new system that takes such a large step backwards?
>>
>> The answer is simply convenience. Imagine a module that contains 100
>> packages and it is obvious that writing a single import statement is far
>> easier than discovering and explicitly writing all the package imports.
>> Yes, IDEs will likely mostly eliminate this issue, but it still makes
>> sense to be able to do this by hand.
>>
>> This proposal is an attempt to maintain the convenience while adding the
>> crucial ability to safely refactor: step 1b is the central idea.
>>
>> // Bryan
>>
More information about the jsr277-eg-observer
mailing list