Towards better serialization

Anthony Vanelverdinghe at
Sat Jun 22 13:46:31 UTC 2019

How about introducing an explicit interface and using the module 
system's services mechanism?
This is an obvious "Why not just ..."-kind of question (i.e. I'm sure it 
has been considered already), so I assume either the idea was dismissed, 
or it was put on the list of "details to be fleshed out". However, I 
can't readily see any flaws in it, and since it allows to do without 
additional encapsulation relaxation, I don't consider it a detail either.

For example, java.base could contain something like:
public record SerializedForm(int version, Object... components) {}

public interface SerializationFactory {
     <T> Function<? super T, SerializedForm> serializer(Class<T> type);
     <T> Function<SerializedForm, ? extends T> deserializer(Class<T> type);

And application modules would `provides SerializationFactory with ...`, 
while serialization frameworks would `uses SerializationFactory`.
Application modules would be free to implement the interface as they see 
fit, but `java.base` could provide a default implementation which would 
work as detailed in the draft (i.e. using reflection and the 
@Serializer/@Deserializer annotations).
Serialization frameworks would then solely rely on `ServiceLoader` to do 
their work.

One issue is that I was unable to implement `SerializationFactory` as 
given above, due to the generics. But I assume pattern matching would 
make this feasible, wouldn't it?

Thanks in advance for any insights,

On 17/06/2019 01:14, Brian Goetz wrote:
>> While I agree that the proposed usage of `open` would be a natural 
>> extension of the existing concept, I was always under the impression 
>> that `open` was intended as a “temporary" migration aid. That 
>> frameworks were supposed to move away from reflection and adopt 
>> solutions based on `MethodHandles.Lookup` instead. So I'm surprised 
>> to see the use of reflection promoted now.
> Two reactions:
>  - First, don't take the paper as something written in stone; it is a 
> first draft.  (A first draft that reflects hundreds of hours of 
> analysis (if not more) by multiple people over multiple years, but a 
> first draft nonetheless.  This is just the first version that reached 
> a level of "doesn't suck" sufficient that it was good enough to share 
> publicly, but I have no illusions that this is in any sense "done" -- 
> it's more that we have finally arrived at the starting line.)  
> Accordingly, the specifics of how fine-grained the relaxation 
> mechanism, are a stake in the ground -- the high order bit here is 
> "there should be some way to identify individual methods as having 
> different dynamic accessibility as static accessibility, allowing 
> private methods in private classes in non-exported packages to still 
> somehow be callable dynamically -- based on an explicit indication in 
> the source."  The exact details are to be determined. Similarly, 
> whether exposed via classic reflection vs Lookup is a detail to be 
> determined.
>  - I think you may have over-rotated towards the "reflection is dead" 
> meme.  Yes, Lookup is "better" because it is explicit, and allows the 
> access checks to be done at lookup time rather than on each 
> invocation.  But, reflection does things that Lookup does not (or at 
> least, not yet); you can't iterate over the methods of a class via a 
> Lookup, let alone interrogate them for their annotations, or query 
> their Signature attributes, or any number of other things frameworks 
> like to do.  So it is likely that frameworks will be using reflection 
> for quite a while, and that's OK.
>> An advantage of open packages, is that they are able to specify whom 
>> they're exporting to. So I can say: `opens foo.ser to 
>> some.ser.framework` and `opens foo.cdi to some.cdi.framework`.
> There's a pretty broad spectrum of granularity possible here.  On the 
> one extreme, you could just say "we don't need open methods, we have 
> open packages -- if you want to serialize, open the package." On the 
> other extreme, you could say that open methods are way too coarse 
> grained; they tar serialization frameworks and dependency injection 
> frameworks and mocking frameworks with the same brush. And there's a 
> lot in the middle.
> There's also a danger that the search for more accurate permission 
> granularity becomes a rathole; for example, the security manager 
> permissions model is quite fine-grained, but in reality people rarely 
> use that mechanism to tailor just the right security policy -- it's 
> too hard, too fussy, too much work, too hard to keep it in sync with 
> what the code actually needs.  So while we might over time attempt to 
> put more structure on "back door APIs", this is probably a good 
> starting position.
> Further, putting "opens X to Y" in the source code may actually 
> require us to name Y before we actually know it; when you're writing a 
> library class, do you really know which serialization frameworks the 
> application into which your library is incorporated will be using?  
> This seems more an issue for application assembly time -- Y is often 
> only known when the entire application is put together -- than of 
> component development time.  But if the `opens` clause is in the 
> source file, we only know what is known at component development time.
> So, yes, there are likely to be more mechanisms to model accessibility 
> on the backdoor API (including, probably, the ability to say things 
> like "I know there are methods in module X that are open, but I still 
> want them encapsulated in MY application") -- but I think its 
> premature at this stage to try to design them now.
> Cheers,
> -Brian

More information about the amber-dev mailing list