I have this MappedSuperClass
@MappedSuperclass
abstract class BaseFoo(
...
) : FooItem {
...
}
sealed interface FooItem
Which is then used like this
@Entity
@Table(name = "bar_1")
class Bar1(
...
) : BaseFoo(
...
) { ... }
@Entity
@Table(name = "bar_2")
class Bar2(
...
) : BaseFoo(
...
) { ... }
@Entity
@Table(name = "all_bar")
class AllBar(
...
@OneToMany(mappedBy = "all_bar", fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE])
val bar1: List<Bar1>? = null,
@OneToMany(mappedBy = "all_bar", fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE])
val bar2: List<Bar2>? = null,
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
val barItems: List<FooItem>
get() = listOfNotNull(bar1, bar2).flatten()
}
I then want to add an exhaustive when statement
val bars = allBarRepository.findById(someId).getOrElse {...}
bars.barItems.forEach {
when (it) {
is Bar1 -> ...
is Bar2 -> ...
}
But the compiler says
‘when’ expression must be exhaustive, add necessary ‘is BaseFoo’ branch or ‘else’ branch instead
I do not want to check for BaseFoo, but only for Bar1 and Bar2 and if there will be more Bar_<INT> for all the other Bars that will be added in the future. I want the compiler to complain when I forget to add any of Bar_<INT> here. By either adding an else branch or checking for BaseFoo this won’t work anymore. I thought this is what sealed interfaces can be used for?
>Solution :
BaseFoo should also be sealed.
sealed class BaseFoo(
...
) : FooItem {
...
}
sealed classes are implicitly abstract, but classes that are only abstract are not sealed. They "open" the hierarchy, and there could be other classes that inherit from BaseFoo.
A bit off topic, but Java’s sealed interfaces/classes require you to specify whether each subclass is sealed/non-sealed/final. I would recommend keeping that in mind when writing Kotlin too. non-sealed would correspond to having no modifier in Kotlin.