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