On Sun, 8 Nov 2020 10:47:08 GMT, Peter Levart <plev...@openjdk.org> wrote:

>>> Simon Roberts wrote:
>> 
>>> This discussion of unmodifiable lists brings me back to the thought that
>>> there would be good client-side reasons for inserting an UnmodifiableList
>>> interface as a parent of LIst, not least because all our unmodifiable
>>> variants from the Collections.unmodifiableList proxy onward fail the Liskov
>>> substitution test for actually "being contract-fulfilling Lists".
>> 
>> At some point there probably will need to be a long article explaining all 
>> the issues here, but at the moment the best writeup I have is this one:
>> 
>> https://stackoverflow.com/a/57926310/1441122
>> 
>> TL;DR there are a few different ways to approach retrofitting something like 
>> this, but they all have enough compromises that the net benefits are unclear.
>
> Hi Stuart,
> 
> I would like to discuss the serialization. You introduce new 
> CollSer.IMM_LIST_NULLS type of immutable collection. This means that if this 
> change goes into JDK16 for example, JDK15 and before will not be able to 
> deserialize such list as they know nothing about IMM_LIST_NULLS even if such 
> lists don't contain nulls. The reason you say to chose new type of 
> serialization format is the following:
> 
>> "Suppose I had an application that created a data structure that used lists 
>> from List.of(), and I had a global assertion over that structure that it 
>> contained no nulls. Further suppose that I serialized and deserizalized this 
>> structure. I'd want that assertion to be preserved after deserialization. If 
>> another app (or a future version of this app) created the structure using 
>> Stream.to
>>  List(), this would allow nulls to leak into that structure and violate that 
>> assertion. Therefore, the result of Stream.toList() should not be 
>> serialization-compatible with List.of() et. al. That's why there's the new 
>> IMM_LIST_NULLS tag in the serial format"
> 
> I don't quite get this reasoning. Let's try to decompose the reasoning giving 
> an example. Suppose we had the following data structure:
> 
> public class Names implements Serializable {
>   private final List<String> names;
>   Names(List<String> names) {
>     this.names = names;
>   }
>   public List<String> names() { return names; }
> }
> 
> App v1 creates such structures using new Names(List.of(...)) and 
> serializes/deserializes them. They keep the invariant that no nulls are 
> present. Now comes App v2 that starts using new Names(stream.toList()) which 
> allows nulls to be present. When such Names instance from app v2 is 
> serialized and then deserialized in app v1, nulls "leak" into data structure 
> of app v1 that does not expect them.
> 
> But the question is how does having a separate CollSer.IMM_LIST_NULLS type 
> prevent that from happening?

I can see that having a separate IMM_LIST_NULLS type might be necessary to 
preserve the allows-null/disallows-null behaviour of indexOf and lastIndexOf 
methods...

NOTE ALSO that while ListN.equals(o) method is using Objects.equals(o1, o2) to 
compare elements, hashCode is inherited from AbstractImmutableList:

        public int hashCode() {
            int hash = 1;
            for (int i = 0, s = size(); i < s; i++) {
                hash = 31 * hash + get(i).hashCode();
            }
            return hash;
        }

...which means it will throw NPE when the list contains null. The same goes for 
SubList.

-------------

PR: https://git.openjdk.java.net/jdk/pull/1026

Reply via email to