2019. január 22., kedd

Kotlin null-biztonság

A kotlin mellett még mindig a szuper-barátságos null-safety a legjobb érvem. Aki esetleg nem ismerné a kotlin nyelvet, Annak röviden:
A kotlin fordítási időben ellenőrzi a változók és értékek típusát.
Azaz mindent úgy kell deklarálnod (a kotlin erősen típusos nyelv) hogy lehet-e null vagy sem.

Például:

var neverNull : String = "bla bla bla"
var maybeNull : String? = null // hoppá alapból pont null

Lehet próbálni a széllel szembe pisilni:

var amISmarterThanTheCompiler : String = null // compiler error

A compiler pedig kikényszeríti a null értékek tiszteletét, azaz mindig kell valami null-ellenőrzést beiktatni. Lehet old-school if(blah!=null) a kotlin elvis-operátorával, vagy a null-safe navigációval, pl

person.taxId?.startsWith("1234") ?: false

A legeslegesleg szeretetre-méltóbb dolog az, hogy ezt adatreprezentációban, a kotlin data osztályokban.

data class Person (
  val firstName : String,
  val lastName: String, 
  val taxId : String?
)

Millió órányi NullPointerException-kergetés után könnyes szemekkel hüppögve kérdezhetjük:

Akkor most meg vagyunk mentve?

És a korrekt válasz: lófaszt. Illetve már majdnem, csak még nem.

Persze azzal kezdtem, hogy fordítási időben ellenőrzi a null-biztonságot. Ebből következően bármi ami nem kotlinból jön, hanem java, groovy, akármi, az megsértheti ezt a szabályt és egy ideig ez ki sem derül.


1. számú gyanúsított: Serialization

A legnyilvánvalóbb tréfát serializationnel lehet elkövetni.

data class Person (
  val firstName : String,
  val lastName: String, 
  @Transient val name = "$firstName $lastname"
)

Tessék kérem serializálni, deserializálni, majd

person.name.startsWith("Meglepi") // bang

2. számú gyanúsított: Jackson 

A jackson egyébként az evidens esetekben kedvesen szól, hogy nem lehet null valami...

data class Person (
  val firstName : String,
  val lastName: String
)

objectMapper.readValue(""" 
 {
   "firstName":"Kakukk",
   "lastName": null
 }
""", Person::class.java)

És itt a jackson felháborodik, amitől mindenki megnyugszik, hogy tessék, biztonságban vagyunk. Igen, majdnem...

data class Person (
  val firstName : String,
  val lastName: String,
  val titles : List
)

val person = objectMapper.readValue(""" 
 {
   "firstName":"Eugene",
   "lastName": "Cuckoo",
   "titles" : ["dr",null,"sir"]
 }
""", Person::class.java)         // nahát, működött...
person.titles.forEach(::println) // bang

Erre többször nyitottak bugot a jackson-kotlin modul bugtrackerében, összegyűlt tekintélyes mennyiségű szavazat. Minden alkalommal a fejlesztő pár hónap után lezárta ugyanazzal a kommenttel: wont fix. A jackson egy java komponens, nem érdekli a kotlin nullsafety.

Egyébként egyre népszerűbbek az egyéb JSON libraryk, mint a moshi... meglátjuk, van időm. Inkáb egy jól ismert lókötő, mint egy civilizált idegen, nem?

3. számú gyanúsított: mindenki

De legyen elég mára ennyi a paranoiából, mert végülis csak annyit akartam mondani, hogy
  1. Semmi baj, túl lehet élni, csak figyelni kell rá.
  2. Mindent addig kell kínozni, amig a kívánt vallomást meg nem teszi.
  3. Oké elég, takarodó