Refactorability proposal...
Bryan Atsatt
bryan.atsatt at oracle.com
Thu Jun 12 10:53:11 PDT 2008
The proposal is to resolve module-->packages at *build* time, not
deploy. This way, the mapping is guaranteed to be valid.
And yes, this does make the sysadmin job a bit more difficult, but that
should be relatively easy to address with tooling.
The main point is that relying on import-by-module at runtime guarantees
that refactoring is problematic. My proposal seems like a reasonable way
to deal with this, but I wanted to start this discussion to explore
others as well.
Any thoughts on how to solve this problem?
// Bryan
Adrian Brock wrote:
> Refactoring:
>
> Aren't there cases where resolving a module import
> into its packages during deployment into the repository
> will break with some refactorings?
>
> I'm not talking about the more stable module refactorings
> where modules are broken into other modules (which
> you seem to be addressing).
>
> This is more development time practices where somebody
> is refactoring module contents. i.e. the importing
> module could end up with a "stale" view of what it
> should be importing.
>
> A not very good example would be my module B imports a module A
> where A exports com.acme.a.interfaces and
> com.acme.a.implementation
> I don't use com.acme.a.implementation explicitly so it
> shouldn't really be one of my constraints.
>
> Somebody then refactors module B such that the
> implementation is now in com.acme.a.impl
> but my module wants to import the now non-existant
> (or at least stale) com.acme.a.implementation.
>
> Overrides in the repository:
>
> I know we avoid these discussions on the list since it
> is really a tooling issue.
>
> But it is a lot easier for a sysadmin to change
> a single version constraint for a module import
> than it is to have to figure out
> what package versions they need to change on the
> package imports and change each one individually.
>
> Basically, the convenience of import-by-module
> extends beyond the development/source code phase.
>
> OSGi/291
>
> There's still going to be a kind of module import
> somewhere to handle OSGi's bundle import constraint.
> i.e. OSGi bundle B issues a request to import bundle A
> which is really a 277 module.
>
> 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