Cílem block functions je vykonat blok kódu v kontextu daného kódu. To znamená, že pokud zavoláte takovou funkci na objektu s lambdou, vytvoří se rozsah (scope), ve kterém můžete k objektu přistupovat bez uvedení jeho jména. Tyto funkce se mezi sebou liší tím, jak je možné k objektu v rámci scope přistoupit a jaký je výsledek celého výrazu.
Kotlin
Kotlin delegated properties
Properties jsou většinou představeny odpovídajícím polem ve třídě (např. val x: Int). Mohou ale být i delegovány. Jejich hodnota je získána od toho, na koho byla tato práce přenesena (delegována). Jinak řečeno getValue a setValue funce zajišťuje delegovaný kód. Delegované vlastnosti se používají deklarováním vlastnosti a delegáta, kterého používají.
Příklad 1
class Example {
var property: Int by Delegate()
}
class Delegate {
var random = Random(0)
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
println("$javaClass - getting random value | thisRef -> $thisRef, property -> $property")
return random.nextInt()
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
println("$javaClass creating new random with seed value: $value | thisRef -> $thisRef, property -> $property")
random = Random(value)
}
}
fun main() {
val e = Example()
println(e.property)
e.property = 10
println(e.property)
}
Rozdíl mezi year-of-era a week-based-year
V rámci java.time.format.DateTimeFormatter je možné použít pro formátování roku malá y a velká Y. Špatně zvolené y může znamenat špatně dohledatelnou chybu. Malé y znamená year-of-era, což vytvoří očekávaný výstup, kdy 31.12. bude vždy jako poslední den v daném roce. Velké Y znamená week-based-year, což v případě týdnu, který spadá do více roků, vytvoří neočekávaný výstup. Pokud Silvestr (či pár předchozích dnů) připadnou do týdne, který nemá 31.12. v sobotu, budou dny poslední dny roku z přelomového týdne patřit do následujího roku. Příklad bude nejlepší. Takto to funguje na Linuxu, ale např. na Window byl výstup s velkým Y pro rok 2021 stejný jako pro malé y.
Anotace @Version v JPA
Sloupec s touto anotací bude navýšen (jeho hodnota) v případě update entity. Pokud hodnoty zůstávají stejné, po update se verze nezvyšuje. Pokud načteme entitu v jednom vlákně a v jiném vlákně ji updatujeme, tak poté v tom prvním vlákně při ukládání dostaneme
Exception in thread "main" javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
Nastavení sloupce v JPA tak, aby jej nešlo updatovat
Anotace @Column umožňuje nastavit sloupec jako neupdatovatelný pomocí updatable = false. V následujícím příkladu je takto nastaven sloupec title.
@Column(unique = true, updatable = false) var title: String = "",
V kódu je sice možné nastavit novou hodnotu
book.title = "New title" book.description = "New description"
sloupec se ale neobjeví ve vygenerovaném sql.
update
t_book
set
description=?
where
id=?
Chyba: TransactionRequiredException Executing an update/delete query
Pro repository test na Micronautovi jsem dostával chybu TransactionRequiredException Executing an update/delete query při exekuci sql skriptu ze souboru.
@Inject lateinit var entityManager: EntityManager ... val fileNameString = "/db/script/$fileName" val sql = this::class.java.getResource(fileNameString)?.readText() entityManager.createNativeQuery(sql).executeUpdate()
Řešením bylo použití SessionFactory a transakcí
@Inject
lateinit var sessionFactory: SessionFactory
...
val fileNameString = "/db/script/$fileName"
val sql = this::class.java.getResource(fileNameString)?.readText()
sessionFactory.openSession()
?.let { session ->
session.entityManagerFactory.createEntityManager()
?.let { entityManager ->
entityManager.transaction.begin()
entityManager.createNativeQuery(sql).executeUpdate()
entityManager.transaction.commit()
}
}
Vararg a spread operátory v Kotlinu
Hvězdička (*) je spread operátor, který rozbalí pole do seznamu hodnot.
Parametr vararg umožňuje předat do funkce libovolné množství argumentů. Každá funkce může mít maximálně jeden vararg operátor.
fun main() {
val lines = arrayOf("First line", "Second line")
printOnLines("")
printOnLines(header = "Header")
printOnLines(header = "Header", lines = lines)
printOnLines(header = "Header", lines = arrayOf("First line", "Second line"))
printOnLines("Header", *lines)
printOnLines(header = "Header", *lines)
printOnLines("Header", "First line", "Second line")
printLines(*lines)
}
fun printOnLines(header: String, vararg lines: String) {
println(header)
println("----------------------------")
lines.forEach {
println(it)
}
}
fun printLines(vararg lines: String) {
lines.forEach {
println(it)
}
}
Měření času v Kotlinu
Pro změření jak dlouho trvá vykonání určitého bloku existují v Kotlinu funkce measureTimeMillis a measureNanoTime. Měřený kód stačí vložit do bloku
val timeMillis = measureTimeMillis {
...
}
println("Completed in $timeMillis ms")
val timeNano = measureNanoTime {
...
}
println("Completed in $timeNano ns")
Nastavení verze pro build projektu v Gradle
Verze projektu, se kterou bude projekt sestaven (build) se nastavuje v souboru build.gradle.kts v části allprojects {}, která slouží pro konfiguraci aktuálního projektu a všech jeho podprojektů.
allprojects {
group = "cz.vitfo"
version = "9.9.1"
...
}
Webflux a BlockHound
BlockHound je java agent (software nahraný JVM před zavoláním main metody), který způsobí to, že pokud v rámci neblokujícího vlákna (vlákno, které nemá volat blokující volání) zavoláte metodu, která blokuje vlákno, vyhodí se chyba.
Závislost
implementation("io.projectreactor.tools:blockhound:1.0.4.RELEASE")
Pokud si chceme BlockHound přizpůsobit, vytvoříme třídu, která implementuje BlockHoundIntegration