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