Hi Jonathan, all,
I've started to look at this changeset. I'm looking at the one Patrick Reinhart
posted a couple weeks ago (! sorry):
http://cr.openjdk.java.net/~reinhapa/reviews/8134373/webrev.01/
I looked at only a few files and I'm already starting to have questions. Not
because anybody did anything wrong, but because there are some subtle issues
that hadn't been raised.
1) ModuleFinder.java
static ModuleFinder compose(ModuleFinder... finders) {
- final List<ModuleFinder> finderList = Arrays.asList(finders);
- finderList.forEach(Objects::requireNonNull);
+ final List<ModuleFinder> finderList = List.of(finders);
return new ModuleFinder() { ...
It's important to note that Arrays.asList() wraps a list around an array,
whereas List.of() has copying semantics. Initially I thought that copying here
is unnecessary, but after further analysis I've come to believe it's necessary.
The compose() method is public in the ModuleFinder interface, and the list is
captured by the ModuleFinder anonymous inner class below, which is returned to
the caller. Therefore, if Arrays.asList() is used, the caller can mutate the
array argument and cause the ModuleFinder instance to misbehave. This is a
TOCTOU problem. Oddly, TOCTOU wasn't discussed with respect to this change,
though it was with another.
In any case switching to the copying semantics of List.of() in this case is
correct and prevents TOCTOU problems.
2) CookieManager.java
The old code created a HashMap and wrapped it in a Collections.unmodifiableMap()
and returned it to the caller. The new code returns some instance created by
Map.of(). This is a public API. While both versions conform to the specification
(it says an "immutable" Map is returned) certain behavioral differences are
visible. In particular, the different objects will serialize differently. It's a
Map<String, List<String>>, and it looks like the values are instances of
ArrayList, so the whole thing will be serializable. It's conceivable that
applications might take this thing and serialize it. This potentially exposes
applications to serial interoperability problems if they wanted to exchange
serial data containing this object between Java 8 and 9.
My hunch is that this problem is fairly unlikely to occur, but I think it would
be good idea to do some searching to see how often this API is used. If it's
used rarely, or the typical usages don't involve storing the result somewhere
(e.g., iterating over the values), then we can proceed.
I use grepcode.com for code searches. I'd be interested in hearing about
alternative code search engines as well.
3) FileTreeIterator.java
Here's the one where a comment was added describing the copying semantics of
List.of in order to prevent TOCTOU problems. The options array is passed from
the outside and thus can be mutated by the caller. But the only time it's used
is within FileTreeWalker, and there it's iterated over once and never used
again. This differs from case (1) above where (in the old code) the array
reference is captured by a long-lived object.
Anyway, in this case, I don't think the copying is necessary, so the old
Arrays.asList() code is probably fine.
4) Not a specific change, but I saw mention upthread of some change that caused
one of the java.time tests to fail, something about 'resolverFields' containing
null. Which change was this, and what's its status in the current webrev?
I note that Stephen Colebourne said that the changes seem "reasonable" but I
don't know if he saw the mention of the java.time test failure, or whether the
changeset he reviewed included a change that would have caused it.
* * *
I still need to look at the other changes. If we end up getting hung up on one
or two, it might make sense to break up the changeset and push part of it. It
might also make sense to split out the java.time changes, since they're a
logical chunk, and they potentially have different reviewers. But no need to do
anything on that just yet.
s'marks
On 9/15/16 12:36 PM, Jonathan Bluett-Duncan wrote:
Hi all,
Stuart, thank you very much for your thorough response.
Regarding serializability concerns, I've just checked my changes and all
non-test code in the JDK which calls it, and it doesn't seem to me that they
affect any fields in `Serializable` classes or the return values of methods
which either return instances of `Serializable` classes or whose javadoc
mention that the returned object is serializable. So I'm somewhat certain that
my changes are serialization-compatible, but only somewhat, because I'm not
that familiar with the intricacies of serialization...
Considering how busy Stuart is, would anyone else be happy to sponsor this
change?
Kind regards,
Jonathan
On 15 September 2016 at 18:20, Stuart Marks <stuart.ma...@oracle.com
<mailto:stuart.ma...@oracle.com>> wrote:
Hi all,
Unfortunately I don't have time to work on any of this at the moment,
because of JavaOne preparation, and JavaOne next week.
Jonathan, thanks for pushing forward with this. I'm glad that others have
picked it up.
Patrick, thanks for posting the changeset on Jonathan's behalf. This is
very helpful.
A few comments regarding issues raised up-thread.
Regarding the (non)singleton-ness of the empty collections, this is covered
by
https://bugs.openjdk.java.net/browse/JDK-8156079
<https://bugs.openjdk.java.net/browse/JDK-8156079>
consider making empty instances singletons
It wasn't a design decision to make them not singletons. The spec
requirement is only that the returned instance satisfy the requirements of
the interfaces it implements (e.g., List) and nothing more. Certainly
there is no spec requirement regarding object identity.
Making the empty collections singletons is the "obvious" thing to do, but
it's often the case that the "obvious" thing isn't the right thing. That
said, it may still be the right thing to make them singletons. Given the
proposed extension to the JDK 9 schedule, it might be possible to change
this in JDK 9.
Note that List.of() should be functionally equivalent to
Collections.emptyList() -- and correspondingly for Set and Map -- but they
do differ. In particular, they have different serialization formats.
Also on this topic, please note comments that Daniel Fuchs and I have added
to
https://bugs.openjdk.java.net/browse/JDK-8134373
<https://bugs.openjdk.java.net/browse/JDK-8134373>
regarding serialization compatibility. Reviewers should take care that
updating code to use these new collection factories doesn't change any
serialization formats. Unfortunately I am not confident that we have
sufficient tests for serialization compatibility.
s'marks
On 9/15/16 7:02 AM, Jonathan Bluett-Duncan wrote:
Wow, lots of discussion went on since I was busy doing other stuff!
Thanks Patrick for doing the work of creating a new webrev for me.
Really
appreciated!
Pavel already mentioned it, but I think List.of instead of
Collections.emptyList in ZoneOffsetTransition is the right thing to do
for
visual and behavioural consistency. If it turns out that we need to
revert
to Collections.empty* and Collections.unmodifiable* for e.g.
serializability or class loading concerns, then I'd be happy to revert
both
of the lines I touched. Otherwise I believe that List.of should be used
consistently.
I think Stuart made List.of() non-singleton because there wasn't any
evidence that it made List.of() more memory- or time-intensive than
Collections.emptyList(), but I might be wrong on this. I'm sure he can
explain more or correct me in this case.
Kind regards,
Jonathan
On 15 September 2016 at 13:33, Patrick Reinhart <patr...@reini.net
<mailto:patr...@reini.net>> wrote:
Hello together,
I tried to process all suggested change input into the following new
webrev:
http://cr.openjdk.java.net/~reinhapa/reviews/8134373/webrev.01
<http://cr.openjdk.java.net/%7Ereinhapa/reviews/8134373/webrev.01>
Give me feedback if something is missing/wrong
-Patrick
On 2016-09-15 13:48, Pavel Rappo wrote:
Daniel, Claes,
List.of() and Collections.emptyList() are not the same. The
behaviours are
different. Moreover, immutable static factory methods return
instances
which are
value-based. I believe it also means we are not tied with
unconditional
instantiation, and in case of empty collections/maps could
probably
return the
same object every time.
We should ask Stuart why it has been done like that in the
first place.
Maybe
out of concern people might synchronize of those objects? I
don't know.
Let's
say for now it's an implementation-specific detail.
On 15 Sep 2016, at 12:35, Claes Redestad
<claes.redes...@oracle.com <mailto:claes.redes...@oracle.com>>
wrote:
+1
I don't mind List.of() aesthetically, but there are places
where
startup/footprint is important where Collections.emptyList()
is simply superior, e.g., constituting permanent data
structures
such as the module graph during early bootstrap.