Obsah
1. Práce s externími Java archivy v programovacím jazyku Clojure
2. První demonstrační příklad – malé zopakování: vložení přeložených tříd do projektu
3. Vytvoření a otestování (uber)archivu s projektem
4. Druhý demonstrační příklad – přidání Java archivu do podadresáře resources
5. Přímé spuštění projektu nástrojem Leiningen a otestování nastavení CLASSPATH
6. Vytvoření a otestování (uber)archivu s projektem
7. Korektní řešení – použití lokálního Maven repositáře
8. Pomocný projekt určený pro vložení externího Java archivu do lokálního Maven repositáře
9. Vygenerování artefaktu pro lokální Maven repositář
11. Třetí demonstrační příklad – přidání závislosti do našeho projektu
12. Vytvoření a otestování (uber)archivu s projektem
13. Odkazy na předchozí části tohoto seriálu
1. Práce s externími Java archivy v programovacím jazyku Clojure
V úvodních částech seriálu o programovacím jazyce Clojure jsme se seznámili s některými možnostmi, které vývojářům nabízí nástroj Leiningen. Připomeňme si jen ve stručnosti, že se jedná o multiplatformního správce projektů, který je rozšiřitelný pomocí takzvaných pluginů a který interně používá Maven, čehož si však mnozí vývojáři ani nemusí všimnout. Mezi základní úlohy, které nástroj Leiningen vývojářům nabízí, patří:
- Vytvoření nového projektu na základě vybrané a předem připravené šablony. K dispozici jsou šablony běžné aplikace (doplněné o jednotkové testy), přídavného modulu pro samotný Leiningen atd. Základním příkazem je lein new.
- Automatické stažení všech knihoven a jejich závislostí na základě konfigurace zapsané do souboru project.clj. Tuto funkci zajistí příkaz lein deps.
- Spuštění projektu s možností předání parametrů příkazového řádku. Příkaz je v tomto případě jednoduchý: lein run.
- Spuštění jednotkových testů, které mohou být vytvořeny společně s projektem (kostra jednoho testu je připravena automaticky). Snadno uhádnutelný příkaz, který testy spustí, se jmenuje lein test.
- Relativně rychlá kontrola syntaxe zdrojových kódů i kontrola existence volaných metod (lein check).
- Lokální instalace projektu do specifikovaného adresáře (lein install).
- Příprava Java archivu (souboru s koncovkou .jar) takovým způsobem, aby bylo možné aplikaci nasadit i na jiném počítači. V rámci přípravy archivu se provádí překlad vybraných modulů do Javovského bajtkódu (lein jar).
- Příprava Java archivu obsahujícího i všechny závislé knihovny včetně samotného Clojure. Takto vytvořený „uberjar“ je posléze možné nasadit na jakémkoli počítači vybaveném pouze JRE (běhovým prostředím jazyka Java). Zajistí příkaz lein uberjar. Právě některými vlastnostmi tohoto příkazu se dnes budeme zabývat.
- Spuštění smyčky REPL s nastavením cest ke všem potřebným knihovnám a modulům (lein repl).
- Diagnostické příkazy, z nichž dnes využijeme především příkazlein classpath určený pro výpis aktuálně nastaveného seznamu cest k třídám a dalším zdrojům.
- Každý příkaz Leiningenu je v rozumné míře popsán v nápovědě (lein help příkaz).
2. První demonstrační příklad – malé zopakování: vložení přeložených tříd do projektu
U většiny projektů, které jsou psány v programovacím jazyce Clojure se nevyhneme nutnosti vhodným způsobem volat metody nějakých tříd vytvořených v Javě a přeložených do bajtkódu, tedy do souborů .class. Samotné vytváření (konstrukce) objektů, volání jejich metod či přístup k atributům je v programovacím jazyce Clojure poměrně jednoduchý, protože lze využít takzvané java interop. Co je ovšem neméně důležité – interpret a překladač jazyka Clojure běží nad virtuálním strojem Javy (JVM), který musí být informován o tom, na kterém místě či místech hledat třídy přeložené do bajtkódu (jedná se o CLASSPATH, s níž se již pravděpodobně všichni vývojáři používající Javu setkali). V případě, že se pro správu projektů psaných v Clojure používá nástroj Leiningen, je nastavení CLASSPATH ponecháno právě tomuto nástroji, což s sebou může přinášet některé problémy, které souvisejí s použitím externích Java archivů. Musíme být totiž schopni:
- Spustit interaktivní smyčku REPL a přitom mít k dispozici všechny potřebné třídy a knihovny.
- Vytvořit JAR archiv bez dalších závislostí, ty se přidají na CLASSPATH.
- Vytvořit „uberjar“ obsahující naprosto všechny závislosti (takový archiv vyžaduje ke svému běhu pouze JVM, nic jiného).
Podívejme se nejdříve na zjednodušený příklad, v němž budeme potřebovat volat javovskou metodu uloženou v bajtkódu (tedy v souboru typu class). Nejdříve vytvoříme kostru nového projektu:
lein new app external-jar-1
Vytvořená kostra projektu je tvořena standardizovanou adresářovou strukturou:
tree . ├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources ├── src │ └── external_jar_1 │ └── core.clj └── test └── external_jar_1 └── core_test.clj 6 directories, 6 files
Nejdůležitější je soubor project.clj, protože jeho obsahem se řídí nástroj Leiningen při provádění všech úkolů:
(defproject external-jar-1 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"]] :main ^:skip-aot external-jar-1.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Do projektu přidáme zdrojový kód třídy naprogramované v Javě. Pro jednoduchost se tento soubor nazvaný PrintHello umístí do podadresáře resources:
tree . ├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources │ └── PrintHello.java ├── src │ └── external_jar_1 │ └── core.clj └── test └── external_jar_1 └── core_test.clj 6 directories, 7 files
Soubor PrintHello.java obsahuje pro jednoduchost třídu s jedinou statickou metodou:
public class PrintHello { public static void printHello() { System.out.println("Hello world!"); } }
Tato statická metoda se volá z hlavního programu (core.clj) následovně:
(ns external-jar-1.core (:gen-class)) (defn -main "Vstupni bod do aplikace." [& args] (PrintHello/printHello))
3. Vytvoření a otestování (uber)archivu s projektem
Aby bylo možné metodu ze třídy PrintHello použít, musíme třídu přeložit (ručně nebo z IDE):
pushd resources javac PrintHello.java popd
Následně můžeme program spustit, a to přímo nástrojem Leiningen:
lein run Hello world!
Vše funguje v pořádku, a to z toho důvodu, že obsah adresáře resources je automaticky uložen na CLASSPATH, o čemž se můžeme velmi snadno přesvědčit:
lein classpath /home/tester/temp/clojure-examples/p1/external-jar-1/test: /home/tester/temp/clojure-examples/p1/external-jar-1/src: /home/tester/temp/clojure-examples/p1/external-jar-1/dev-resources: /home/tester/temp/clojure-examples/p1/external-jar-1/resources: /home/tester/temp/clojure-examples/p1/external-jar-1/target/base+system+user+dev/classes: /home/tester/.m2/repository/clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.jar: /home/tester/.m2/repository/org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.jar: /home/tester/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar
Při distribuci programu popř. před jeho nasazením na testovací a produkční servery se většinou provádí vytvoření „uberjaru“, který obsahuje jak vlastní program v Clojure přeložený do bajtkódu, tak i všechny závislé knihovny, včetně knihoven samotného Clojure. Vytvoření „uberjaru“ je jednoduché a zajistí ho následující tři příkazy (ve skutečnosti postačuje použít jen příkaz poslední, ovšem vyčištěním adresáře target se nic nezkazí):
lein clean lein deps lein uberjar
Výsledek je uložený v adresáři target/uberjar/, takže ho lze snadno otestovat:
java -jar target/uberjar/external-jar-1-0.1.0-SNAPSHOT-standalone.jar Hello world!
Proč tento program funguje, tj. proč není problém s načtením třídy PrintHello osvětlí náhled do vytvořeného Java archivu:
unzip -l target/uberjar/external-jar-1-0.1.0-SNAPSHOT-standalone.jar |grep PrintHello 117 2016-09-12 19:09 PrintHello.java 407 2016-09-12 21:17 PrintHello.class
4. Druhý demonstrační příklad – přidání Java archivu do podadresáře resources
Ve druhém demonstračním příkladu si situaci poněkud zesložitíme, protože namísto pouhých .class souborů budeme chtít do projektu přidat celý Java archiv. Opět si pro začátek vytvoříme kostru nového projektu:
lein new app external-jar-2
Soubor src/external_jar2/core.clj vypadá stále stejně, samozřejmě až na rozdílné jméno projektu:
(ns external-jar-2.core (:gen-class)) (defn -main "Vstupni bod do aplikace." [& args] (PrintHello/printHello))
Do adresáře resources však vložíme pouze Java archiv a pro jistotu vymažeme původní zdrojový kód i vygenerovaný bajtkód:
pushd resources javac PrintHello.java jar cvf PrintHello.jar PrintHello.class added manifest adding: PrintHello.class(in = 407) (out= 278)(deflated 31%) rm PrintHello.java PrintHello.class popd
Struktura projektu nyní vypadá následovně:
. ├── doc │ └── intro.md ├── LICENSE ├── project.clj ├── README.md ├── resources │ └── PrintHello.jar ├── src │ └── external_jar_2 │ └── core.clj └── test └── external_jar_2 └── core_test.clj 6 directories, 7 files
5. Přímé spuštění projektu nástrojem Leiningen a otestování nastavení CLASSPATH
Java archiv s testovací třídou PrintHello je vytvořen a uložen do správného adresáře resources, takže by se mohlo zdát, že je vše v pořádku. Při pokusu o spuštění aplikace však dojde k chybě:
lein run Exception in thread "main" java.lang.RuntimeException: No such namespace: PrintHello, compiling:(external_jar_2/core.clj:9:5) at clojure.lang.Compiler.analyze(Compiler.java:6464) at clojure.lang.Compiler.analyze(Compiler.java:6406) ... ... ... ... spousta více či méně neužitečných řádků :-) ... ... ... at clojure.main.main(main.java:37) Caused by: java.lang.RuntimeException: No such namespace: PrintHello at clojure.lang.Util.runtimeException(Util.java:221) at clojure.lang.Compiler.resolveIn(Compiler.java:6910) at clojure.lang.Compiler.resolve(Compiler.java:6884) at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6845) at clojure.lang.Compiler.analyze(Compiler.java:6427) ... 52 more
Proč k chybě došlo osvětlí nám již známý diagnostický příkaz:
lein classpath /home/tester/temp/clojure-examples/p1/external-jar-2/test: /home/tester/temp/clojure-examples/p1/external-jar-2/src: /home/tester/temp/clojure-examples/p1/external-jar-2/dev-resources: /home/tester/temp/clojure-examples/p1/external-jar-2/resources: /home/tester/temp/clojure-examples/p1/external-jar-2/target/base+system+user+dev/classes: /home/tester/.m2/repository/clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.jar: /home/tester/.m2/repository/org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.jar: /home/tester/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar
Vidíme, že nikde není nastavena přímá cesta k souboru PrintHello.jar! Jak ji však lze nastavit? Pokud bychom spouštěli JVM standardní cestou, stačilo by samozřejmě ruční nastavení CLASSPATH, ovšem při použití projektu Leiningen, který se stará o inicializaci JVM, je nutné použít odlišné řešení, a to konkrétně úpravu projektového souboru project.clj. Povšimněte si zvýrazněného řádku:
(defproject external-jar-2 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"]] :main ^:skip-aot external-jar-2.core :target-path "target/%s" :resource-paths ["resources/PrintHello.jar"] :profiles {:uberjar {:aot :all}})
Za klíčem :resource-paths je vektor cest k Java archivům i dalším prostředkům. Zkusme test znovu:
lein run Hello world!
Výborně, ještě si pro jistotu vypišme nastavení cest:
/home/tester/temp/clojure-examples/p1/external-jar-2/test: /home/tester/temp/clojure-examples/p1/external-jar-2/src: /home/tester/temp/clojure-examples/p1/external-jar-2/dev-resources: /home/tester/temp/clojure-examples/p1/external-jar-2/resources/PrintHello.jar: /home/tester/temp/clojure-examples/p1/external-jar-2/target/base+system+user+dev/classes: /home/tester/.m2/repository/clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.jar: /home/tester/.m2/repository/org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.jar: /home/tester/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar
Vše je – alespoň pro tuto chvíli – v pořádku.
6. Vytvoření a otestování (uber)archivu s projektem
Vzhledem k tomu, že přímé spuštění aplikace nástrojem Leiningen bylo úspěšné, mohlo by se zdát, že stejně úspěšné bude i vytvoření „uberjaru“ a jeho případné nasazení na testovací server. Pojďme si tedy celý proces odzkoušet, a to již známými kroky popsanými v předchozích kapitolách:
lein clean lein deps lein uberjar
Očekávaný „uberjar“ se skutečně vytvořil, a to opět v podadresáři targets, ovšem při pokusu o spuštění aplikace již nebudeme tak úspěšní:
java -jar target/uberjar/external-jar-2-0.1.0-SNAPSHOT-standalone.jar Exception in thread "main" java.lang.NoClassDefFoundError: PrintHello at external_jar_2.core$_main.doInvoke(core.clj:6) at clojure.lang.RestFn.invoke(RestFn.java:397) at clojure.lang.AFn.applyToHelper(AFn.java:152) at clojure.lang.RestFn.applyTo(RestFn.java:132) at external_jar_2.core.main(Unknown Source) Caused by: java.lang.ClassNotFoundException: PrintHello at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 5 more
Příčinu tohoto neúspěchu musíme hledat v tom, že se obsah podadresáře resources při tvorbě Java archivu („uberjaru“) prostě bez dalších zásahů vloží do vytvářeného archivu, takže vlastně získáme „JAR v JARu“, což v tomto případě není korektní a zejména to není příjemné pro případné uživatele aplikace. Ostatně můžeme si to vyzkoušet sami:
unzip -l target/uberjar/external-jar-2-0.1.0-SNAPSHOT-standalone.jar | grep PrintHello 743 2016-09-12 19:13 PrintHello.jar
7. Korektní řešení – použití lokálního Maven repositáře
Vzhledem k tomu, že nástroj Leiningen interně používá Maven repositáře, spočívá (pravděpodobně jediné) korektní řešení v tom, že z externího Java archivu, který budeme chtít do projektu přidat, vytvoříme v lokálním Maven repositáři, který většinou nalezneme v adresáři ~/.m2, nový artefakt. Tento adresář by měl být vytvořen minimálně ve chvíli instalace Leiningenu; pokud však adresář ~/.m2 nemůžete nalézt, vypište si nastavení proměnné prostředí M2_HOME, zda neukazuje na jiný adresář. Vraťme se však k našemu problému. Pokud máme nějaký Java archiv – typicky to bývají databázové drivery, k nimž nutně nemusí existovat zdrojové kódy – a potřebujeme ho distribuovat či nasazovat společně s aplikací, lze toho dosáhnout korektnějším způsobem, než pouhým uložením Java archivu do podadresáře resources. Doporučený způsob se skládá ze čtyř kroků:
- Použití pomocného projektu založeného na pluginu nazvaném lein-localrepo.
- Vygenerování artefaktu s Java archivem v lokálním Maven repositáři.
- Vložením příslušného řádku se jménem a verzí knihovny do projektového souboru (klíč :dependencies v souboru project.clj).
- Vytvořením „uberjaru“, který nyní bude mít korektní obsah.
Jednotlivé kroky si podrobněji popíšeme v navazujících kapitolách.
8. Pomocný projekt určený pro vložení externího Java archivu do lokálního Maven repositáře
Prvním krokem je vytvoření pomocného projektu, který nám bude sloužit pouze pro vygenerování lokálních artefaktů. Striktně řečeno vlastně ani není nezbytně nutné tento pomocný projekt vytvářet a používat, protože příslušný plugin lze specifikovat v libovolném jiném projektu, ale striktním oddělením tvorby artefaktu od zbytku „hlavního“ projektu můžeme celé problematice lépe porozumět. Vytvořme si tedy kostru zpočátku zcela prázdného projektu:
lein new app maven-artefact-generator
Následně provedeme úpravu projektového souboru přidáním klíče :plugins. Obsahem tohoto klíče je vektor, přičemž každý prvek vektoru specifikuje jeden plugin pro nástroj Leiningen. Na pluginy se můžeme dívat také jako na běžné knihovny, které ovšem do Leiningenu přidávají další cíle (při volání z CLI nové příkazy, ostatně již jsme si popisovali plugin codox či cloverage):
(defproject teiid-module "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "GNU General Public License" :url "https://gnu.org/licenses/gpl.html"} :dependencies [[org.clojure/clojure "1.7.0"]] :plugins [[lein-localrepo "0.5.3"]] :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Nově požadovaný plugin si i s jeho závislostmi stáhneme:
lein deps
Nyní je tento pomocný projekt připraven a můžeme ho použít pro vytvoření artefaktů pro lokální Maven repositář.
9. Vygenerování artefaktu pro lokální Maven repositář
Podívejme se nyní na způsob vytvoření nového artefaktu. Nejprve do adresáře pomocného projektu zkopírujeme soubor PrintHello.jar, který jsme vytvořili ve čtvrté kapitole. Následně použijeme příkaz lein localrepo. Jak již zajisté tušíte, je tento nový příkaz zajišťován právě díky pluginu lein-localrepo a bude tedy fungovat pouze tehdy, když se nacházíme v daném projektu (o tom se ostatně sami můžete přesvědčit spuštěním příkazu lein bez parametrů uvnitř projektu a mimo pomocný projekt).
Příkaz lein localrepo nabízí několik variant spuštění. My konkrétně využijeme variantu install, které se předá název Java archivu, název artefaktu a jeho verze (tyto dva údaje si zapamatujte):
lein localrepo install resources/PrintHello.jar PrintHello 1.0.0
V adresáři s artefakty by se měl po zadání tohoto příkazu objevit nový podadresář PrintHello s následujícím obsahem:
tree ~/.m2/repository/PrintHello /home/tester/.m2/repository/PrintHello └── PrintHello ├── 1.0.0 │ ├── _maven.repositories │ ├── PrintHello-1.0.0.jar │ └── PrintHello-1.0.0.pom └── maven-metadata-local.xml 2 directories, 4 files
10. Vytvořený artefakt
Zajímavé (i když nikoli nezbytné!) může být prozkoumání XML souborů s metadaty o nové knihovně:
cat ~/.m2/repository/PrintHello/PrintHello/maven-metadata-local.xml <?xml version="1.0" encoding="UTF-8"?> <metadata> <groupId>PrintHello</groupId> <artifactId>PrintHello</artifactId> <versioning> <release>1.0.0</release> <versions> <version>1.0.0</version> </versions> <lastUpdated>20160912174143</lastUpdated> </versioning> </metadata>
A dále pak prozkoumání souboru popisujícího artefakt:
cat ~/.m2/repository/PrintHello/PrintHello/1.0.0/PrintHello-1.0.0.pom <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>PrintHello</groupId> <artifactId>PrintHello</artifactId> <version>1.0.0</version> <name>PrintHello</name> </project>
11. Třetí demonstrační příklad – přidání závislosti do našeho projektu
Nyní si ukažme, jakým způsobem se vlastně nový modul použije. Je to ve skutečnosti velmi jednoduché až triviální, protože všechny potřebné znalosti již známe z dřívějška. Postačuje do projektu vložit zvýrazněný řádek a současně odstranit předchozí řádek s klíčem :resource-paths. Projektový soubor může vypadat následovně:
(defproject external-jar-3 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] [PrintHello "1.0.0"]] :main ^:skip-aot external-jar-3.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Příkaz lein deps se již nebude pokoušet o hledání modulu PrintHello, protože ho v adresáři ~/.m2 nalezne (samozřejmě musíte použít shodné jméno i číslo verze!).
Projekt půjde přímo spustit:
lein run Hello world!
Zajímavé je nastavení CLASSPATH (opět zvýrazním, řádek, který je v tuto chvíli důležitý):
/home/tester/temp/clojure-examples/p1/external-jar-3/test: /home/tester/temp/clojure-examples/p1/external-jar-3/src: /home/tester/temp/clojure-examples/p1/external-jar-3/dev-resources: /home/tester/temp/clojure-examples/p1/external-jar-3/resources: /home/tester/temp/clojure-examples/p1/external-jar-3/target/base+system+user+dev/classes: /home/tester/.m2/repository/clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.jar: /home/tester/.m2/repository/org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.jar: /home/tester/.m2/repository/PrintHello/PrintHello/1.0.0/PrintHello-1.0.0.jar: /home/tester/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar
12. Vytvoření a otestování (uber)archivu s projektem
V tento okamžik již Leiningen pracuje s modulem PrintHello stejně jako s jakýmkoli jiným modulem, takže můžeme bez problémů vytvořit funkční „uberjar“:
lein clean lein deps lein uberjar
Spuštění aplikace z vytvořeného Java archivu proběhne bez chyby:
java -jar target/uberjar/external-jar-2-0.1.0-SNAPSHOT-standalone.jar Hello world!
Výpisem obsahu Java archivu zjistíme, že v tomto případě již nemáme „JAR v JARu“, ale správný obsah:
unzip -l target/uberjar/external-jar-3-0.1.0-SNAPSHOT-standalone.jar | grep PrintHello 407 2016-09-12 19:12 PrintHello.class
Poznámka: na rozdíl od prvního příkladu se v Java archivu nenachází původní zdrojový soubor PrintHello.java, a to samozřejmě z toho důvodu, že tento soubor nebyl uložen do PrintHello.jar.
13. Odkazy na předchozí části tohoto seriálu
- Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
14. Odkazy na Internetu
- Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - Clojars:
https://clojars.org/ - Seznam knihoven na Clojars:
https://clojars.org/projects - Zip archiv s Clojure 1.8.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip - Clojure 1.8 is now available
http://clojure.org/news/2016/01/19/clojure18 - Changes to Clojure in Version 1.8
https://github.com/clojure/clojure/blob/master/changes.md - Clojure core.async
http://www.infoq.com/presentations/clojure-core-async - core.async API Reference
https://clojure.github.io/core.async/ - Clojure core.async Channels
http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html - core.async examples
https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj - Timothy Baldridge – Core.Async
https://www.youtube.com/watch?v=enwIIGzhahw