Consider following Kotlin code:
data class CachedUserData(var contracts: MutableList<String>) {
var localDateTime: LocalDateTime = LocalDateTime.now()
}
When I'm trying to get via auto-generated getter contracts list and modify it from outside, I'm getting exception thrown java.lang.UnsupportedOperationException: null. Investigation shows, that in this class the contracts field is being initialized to type ImmutableCollections$ListN.
I'm able to bypass this by adding following data modification function:
fun addContract(item: String) {
val newList = mutableListOf(*contracts.toTypedArray());
newList.add(item);
contracts = newList;
}
then, this type directly after this class construction is ImmutableCollections$ListN, but after it's modification via this function call is changed to ArrayList and stays that way.
The instance of this particular class is created as a result of network resource fetch (plain Java List), that is afterwards being passed by stream to some filtering, and afterwards is being collected by .toList() Java collector.
My questions would be:
- Why initial type is set to ImmutableCollection, even I'm trying to strongly persuade Kotlin that I'd love to have this list to be modifiable?
- Is there a way to make it initially make them modifiable and use simple construct of
.getContracts().add(value);? - Is there a place, where such behavior is described in details? I.e. some implicit collections conversions to some immutable shadowing types?
Edit:
This class is instantiated in some Java part of project, and it's supplied with List<String> type as input parameter:
Many thanks in advance!
Java does not have an extra type to distinguish mutable lists from immutable lists. All lists, mutable or immutable are represented by the
java.util.Listtype. In Kotlin, bothListandMutableListare mapped tojava.util.Listinterface in Java. See the mapping table here.Even if you say your class' constructor should take a
MutableListin Kotlin, the constructor takes ajava.util.Listas far as Java is concerned. Therefore, code in Java can pass both mutable and immutable lists to it.You said that the Java code is passing the result of a
Stream.toListcall to the constructor, and that is the problem -toListis designed to return an immutable list:You should instead use
Collectors.toCollectionto control the type of the list that is returned, and pass in a supplier of a mutable list type.Alternatively, instead of making a mutable copy of the list in
addContract, you can do this in aninitblock instead: