Zadanie 1 — reflexia

Ciele

  1. Naučiť sa používať reflexiu v jazyku Java.
  2. Naučiť sa vytvárať modulárnu architektúru knižnice.

Úloha

Úlohou je vytvorenie knižnice realizujúcej perzistenciu – ukladanie objektov do databázy. Ide o veľmi jednoduchý ORM (object-relational mapper). Knižnica umožní definovať jednoduché dátové triedy reprezentujúce databázové tabuľky s tým, že objekt triedy bude zodpovedať riadku tabuľky.

API knižnice

API knižnice predstavuje trieda ReflectivePersistenceManager implementujúca rozhranie PersistenceManager. Jej konštruktor očakáva objekt pripojenia k databáze. Trieda má poskytovať metódy:

  • void createTables(Class<?>... types) – vytvorenie tabuliek v databáze (ak neexistujú),
  • <T> Optional<T> get(Class<T> type, long id) – získanie entity z databázy na základe primárneho kľúča,
  • <T> List<T> getAll(Class<T> type) – získanie všetkých entít daného typu,
  • void save(Object entity) – vloženie entity do databázy alebo jej aktualizácia,
  • void delete(Object entity) – odstránenie entity z databázy (na základe primárneho kľúča).

Všetky metódy v prípade chyby majú vyhadzovať výnimku PersistenceException.

Metóda createTables() má používať príkaz CREATE TABLE IF NOT EXISTS, ktorý zabezpečí, že tabuľky sa nevytvoria v prípade, že už existujú.

Metóda save() v sebe spája funkcionalitu SQL príkazov INSERT a UPDATE. Logika výberu príkazu je veľmi jednoduchá:

  • Ak hodnota primárneho kľúča v objekte je rovná 0, potom predpokladáme, že objekt nebol načítaný z databázy, a teda je potrebné ho do databázy pridať (INSERT).
  • Ak hodnota primárneho kľúča je rôzna od 0, potom predpokladáme, že objekt v databáze už je uložený a je potrebné ho aktualizovať (UPDATE).

V prípade vloženia nového objektu do databázy je nutné zároveň aktualizovať hodnotu jeho primárneho kľúča na tú, ktorá mu bola pridelená databázou. Tým sa zabezpečí, že opakované volanie save() s tým istým objektom už zabezpečí iba aktualizáciu.

Entitné triedy

Všetky dátové členy budú uložené do databázy. PersistenceManager musí vedieť ukladať členské premenné základných primitívnych typov (int, double) a reťazcov (String).

Členská premenná s názvom id reprezentuje primárny kľúč. Typ primárneho kľúča musí byť long. Hodnota primárneho kľúča sa nastaví automaticky pri prvom uložení objektu do databázy. V databáze musí byť primárny kľúč označený ako PRIMARY KEY AUTOINCREMENT.

SQLite na rozdiel od iných databáz používa dynamické typovanie a typ stĺpca definuje iba odporúčaný typ dát s predvolený spôsob ukladania. Preto stačiť používať tieto typy stĺpcov (afinity):

  • INTEGER pre všetky celočíselné typy,
  • REAL pre float a double,
  • TEXT pre String.

Ak trieda obsahuje referenciu, v databáze sa tento vzťah uloží pomocou cudzieho kľúča. Pri vyberaní objektov z databázy sa automaticky vyberú aj referované objekty. Pritom polymorfizmus nemusí byť podporovaný.

Názov stĺpca sa v tejto iterácii musí zhodovať s názvom členskej premennej (aj v prípade cudzieho kľúča).

Návrh a implementácia

Pri implementácii sa snažte dosiahnuť modulárnosť vášho riešenia. Berte ohľad na to, že v ďalších zadaniach bude potrebné doplniť ďalší spôsob analýzy tried (anotačný procesor namiesto reflexie), a neskôr aj spôsob práce s entitami (generovanie kódu namiesto reflexie). Dobré členenie na moduly by vám malo pomôcť realizovať tieto zmeny.

Kostra riešenia

Konfigurácia projektov Gradle a rozhranie PersistenceManager

Odovzdanie

Zadanie je potrebné vypracovať v priradenom projekte v Gitlabe do konca 13. marca.