Ciele
- Naučiť sa používať reflexiu v jazyku Java.
- 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
prefloat
adouble
,TEXT
preString
.
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.