CodeGym /Kurse /Java Server /Ruhig dependencies {} bearbeiten

Ruhig dependencies {} bearbeiten

Java Server
Level 3, Lektion 3
Verfügbar

1. build.gradle.kts: Block für Block lesen

Wir haben jetzt drei Stützen: plugins{} ändert das Build-Verhalten, repositories{} sagt, wo Bibliotheken gesucht werden, dependencies{} listet auf, was das Projekt braucht. Jetzt brauchen wir keine neue Theorieschleife, sondern die Fähigkeit, schnell in der Datei zu navigieren: Wo bist du gerade und welchen Block bearbeitest du überhaupt.

Zur Orientierung diese „Karte" der Datei:

Block Welche Frage er beantwortet Einfache Assoziation
plugins {}
„Welche Möglichkeiten hat der Build?" Welche Werkzeuge im Kasten liegen
repositories {}
„Woher Bibliotheken laden?" In welchen Laden man geht
dependencies {}
„Was genau laden und wohin legen?" Was man kauft und in welches Regal zu Hause

Ein minimales „Skelett" sieht ungefähr so aus:

plugins {
    // Grundlegende Möglichkeiten eines Java-Projekts (Kompilierung, Tests usw.)
    java

    // Möglichkeit, die Anwendung über `gradlew run` zu starten
    application
}

repositories {
    // Maven Central – das wichtigste öffentliche Repository für Java-Bibliotheken
    mavenCentral()
}

dependencies {
    // Noch leer – aber nicht lange: hier kommen Projektbibliotheken
}

Wichtig, eine Feinheit zu bemerken: dependencies{} „lebt nicht für sich allein". Konfigurationen wie implementation erscheinen, weil das Java-Plugin das Java-Standard-Projektmodell mitbringt. Beim Bearbeiten reicht es meistens, das einfache Bild zu kennen: Plugins legen das Build-Verhalten fest, Repositories die Bibliothekssuche, Abhängigkeiten die Classpath-Zusammensetzung.

2. Abhängigkeitszeile: Rolle und Koordinaten

Eine Zeile in dependencies{} sind nur zwei Dinge: die Rolle der Abhängigkeit und ihre Koordinaten. Wenn man diese kurze Formel im Kopf behält, wird das Bearbeiten der Build-Datei viel ruhiger.

<Konfiguration>("group:artifact:version")

Zum Beispiel:

dependencies {
    // Jackson: Bibliothek für die Arbeit mit JSON (im Hauptcode gebraucht)
    implementation("tools.jackson.core:jackson-databind:3.0.4")
}

Wörtlich gelesen: „Für den Hauptcode des Projekts (implementation) brauche ich die Bibliothek mit den Koordinaten tools.jackson.core:jackson-databind:3.0.4."

In Kotlin DSL sieht das aus wie ein Funktionsaufruf: implementation(...). Typische Fehler sind daher meistens rein syntaktisch wie normaler Code: Anführungszeichen vergessen, schließende Klammer vergessen oder versehentlich einfache Anführungszeichen statt doppelter. Gradle wird in so einem Fall nicht „erraten, was gemeint war", sondern ehrlich sagen: „Diese Datei verstehe ich nicht."

3. dependencies{} in kleinen Schritten bearbeiten

Das häufigste Problem bei Einsteigern liegt nicht daran, dass sie „Abhängigkeiten nicht verstehen", sondern dass sie die Datei auf einmal um 20 Zeilen ändern, Gradle dann abbricht und das Rätselraten beginnt: „Welche der zwanzig Zeilen hat es nicht verdaut?" Daher ist die goldene Regel dieser Lektion sehr einfach: Ändere immer nur eine Sache auf einmal und prüfe dann, ob das Projekt noch gebaut wird und startet.

Ein ruhiges Arbeitsszenario läuft meistens so ab. Du öffnest build.gradle.kts, suchst dependencies{} (Suche nach dem Wort dependencies – das ist kein Versagen, sondern professionelle Faulheit), fügst genau eine Zeile hinzu, speicherst, lässt die IDE die Änderungen übernehmen oder führt einfach den bekannten Gradle-Befehl aus Level 2 aus (z. B. ./gradlew run). Wenn alles stimmt – perfekt, weiter. Wenn nicht – du weißt genau, welche Zeile schuld ist, weil du genau sie zuletzt hinzugefügt hast.

Ein sauberes Hinzufügen einer Abhängigkeit kann so aussehen:

dependencies {
    // SLF4J – das ist die Logging-API (die Implementierung binden wir separat ein)
    implementation("org.slf4j:slf4j-api:2.0.17")
}

Wenn Gradle danach sagt, es kann die Abhängigkeit nicht finden, bedeutet das fast immer eines von drei Dingen: Tippfehler in den Koordinaten, fehlendes Repository (kein mavenCentral()) oder falsche Koordinaten bzw. Version der Bibliothek. Und das ist auch angenehm: Probleme gibt es meistens nicht tausend, sondern nur wenige Typen – nur in unterschiedlichen Verkleidungen.

Eine kleine Gewohnheit, die sich schnell auszahlt: Nach einer Änderung an build.gradle.kts, wenn alles funktioniert, einen kleinen Git-Commit machen. Nicht weil „man das so macht", sondern weil das der billigste Weg ist, einen „Zurück zum funktionierenden Zustand"-Knopf zu haben – ohne Tränen und Drama.

4. Lesbarkeit von dependencies{}: Reihenfolge und Gruppen

Gradle ist meistens egal, in welcher Reihenfolge die Zeilen in dependencies{} stehen, aber Menschen interessiert es sehr. Und das ist normal: Nach einer Woche öffnest du die Datei und möchtest verstehen, was hier passiert, ohne das Rätsel „Finde Jackson im Chaos" zu lösen. Deshalb machen wir den Abhängigkeitsblock nicht nur funktionierend, sondern auch lesbar – besonders in einem Lernprojekt, wo jede nächste Ebene auf der vorherigen aufbaut.

Schau dir die „chaotische" Variante an. Sie kann funktionieren, aber lesen ist unangenehm – wie ein Buch, dessen Seiten durchgemischt wurden:

dependencies {
    // Beispiel: alles durcheinander – Gradle überlebt es, aber ein Mensch wird leiden
    runtimeOnly("ch.qos.logback:logback-classic:1.5.32")
    implementation("tools.jackson.core:jackson-databind:3.0.4")
    implementation("org.slf4j:slf4j-api:2.0.17")
    implementation("tools.jackson.core:jackson-core:3.0.4")
    runtimeOnly("ch.qos.logback:logback-core:1.5.32")
}

Jetzt derselbe Inhalt, aber menschenfreundlich: Ähnliche Bibliotheken stehen zusammen, es gibt kleine Trennkommentare und Leerzeilen zwischen semantischen Gruppen. Das ist kein „Zauber" mehr, sondern ein Dokument:

dependencies {
    // JSON
    implementation("tools.jackson.core:jackson-core:3.0.4")
    implementation("tools.jackson.core:jackson-databind:3.0.4")

    // Logging
    implementation("org.slf4j:slf4j-api:2.0.17") // API: Code wird darauf verweisen
    runtimeOnly("ch.qos.logback:logback-classic:1.5.32") // Implementierung: zur Laufzeit gebraucht
    runtimeOnly("ch.qos.logback:logback-core:1.5.32") // Im Kurs-Baseline explizit neben classic belassen
}

Wichtig dabei: Kommentare nicht zum Roman machen. Kurze Markierungen wie // JSON und // Logging reichen. Das sind wie Aufschriften auf Umzugskartons: Man schreibt nicht „Karton Nr. 7 mit verschiedenen Gegenständen, die theoretisch nützlich sein könnten", sondern „KÜCHE" – und jedem ist sofort geholfen.

Noch ein nützliches Prinzip: Halte „Bibliotheksfamilien" zusammen. Wenn zwei Abhängigkeiten dieselbe group haben, sind sie fast sicher logisch verbunden. Das ist keine absolute Regel, aber in einem Lernprojekt funktioniert es gut und macht die Blockstruktur offensichtlich.

5. Mini-Fallbeispiel: ReadLater Starter und wachsende Abhängigkeiten

Im ReadLater Starter gehen wir bewusst Schritt für Schritt vor: Zuerst das Gerüst, dann Grundkenntnisse über Abhängigkeiten, dann erst echte Bibliotheken. Unser Ziel jetzt ist nicht, „alles auf der Welt einzubinden", sondern dependencies{} so vorzubereiten, dass er morgen und in einer Woche noch sauber und erklärbar aussieht.

Stell dir vor, du öffnest die Datei und willst zwei Dinge verstehen: „Was gehört zu JSON?" und „Was gehört zu Logs?" Wenn der Block bereits gruppiert ist, findet man die Antwort in 3 Sekunden. Wenn alles durcheinander ist, wandern die Augen durch die Datei und man verschwendet Energie nicht auf das Verstehen des Backend-Themas, sondern auf die Suche nach den richtigen Zeilen.

Daher ist es im Rahmen von ReadLater Starter nützlich, den Abhängigkeitsblock als kleine Karte zu halten. Auch wenn man heute nur eine Bibliothek hinzugefügt hat, kann man sofort die Struktur vorbereiten, damit man sie später nicht im Eifer des Gefechts zusammenstückeln muss. Zum Beispiel ist so ein Gerüst durchaus normal:

dependencies {
    // Hier kommen Abhängigkeiten für JSON

    // Hier kommen Abhängigkeiten fürs Logging

    // Testabhängigkeiten (noch leer)
}

Ja, das sieht aus wie leere Kartons. Aber das sind ehrliche leere Kartons, die nach ein paar Lektionen inhaltsvoll werden – und dabei bleibt die Lesbarkeit der Datei erhalten. Und hier ist ein kleiner praktischer Aspekt: Man beginnt, das Projekt nicht als „Sammlung von Zeilen" zu sehen, sondern als Struktur, die man kontrolliert.

6. Typische Fehler beim Bearbeiten von dependencies{}

Fehler in dependencies{} sind meistens keine „schwierigen", sondern die menschlichsten: Man ist in Eile, kopiert einen Ausschnitt aus dem Internet, liest nicht zu Ende, wo er hingehört, und bekommt den roten Gradle-Bildschirm. Das ist normal. Wichtig ist es, solche Fehler nicht zu fürchten und schnell zu verstehen, was genau kaputt ist – fast wie bei normalem Java-Code.

Fehler Nr. 1: Versuchen, Abhängigkeiten in den Block plugins{} zu schreiben.
Das ist die klassische Verwechslung: Man sieht eine Zeile der Form something("group:artifact:version") und denkt, das sei „auch etwas über Plugins." Aber die Regel ist einfach: Plugins beschreiben das Build-Verhalten, Bibliotheken für Code gehören in dependencies{}. Wenn man eine Bibliothek in plugins legt, wird Gradle nicht „raten" – es weigert sich einfach zu verstehen.

Fehler Nr. 2: Eine halbe Datei auf einmal bearbeiten und dann nicht wissen, welche Zeile alles kaputtgemacht hat.
Wenn man gleichzeitig fünf Bibliotheken hinzufügt, die Reihenfolge ändert, Altes kommentiert und nebenbei noch Repositories ändert, beraubt man sich selbst einer normalen Diagnose. Ein kleiner Schritt – eine verständliche Prüfung. Das ist viel langweiliger, aber verwandelt den Build nicht in eine Lotterie.

Fehler Nr. 3: Eine Abhängigkeit duplizieren oder eine alte Version daneben „für alle Fälle" stehen lassen.
So tauchen schnell fast identische Zeilen in der Datei auf, und nach ein paar Tagen ist unklar, welche davon die funktionierende und welche ein zufälliger Überrest ist. Eine gute Gewohnheit: Nach der Änderung den ganzen Block einmal vollständig durchlesen und alles entfernen, was überflüssig geworden ist.

Fehler Nr. 4: runtimeOnly verwenden und dann Klassen dieser Bibliothek im Hauptcode importieren.
Das ist eine tückische Falle. runtimeOnly bedeutet: Die Bibliothek ist beim Start im Classpath, aber nicht zwingend bei der Kompilierung. Wenn du versuchst, ein import ... aus so einer Abhängigkeit zu schreiben, kann die Kompilierung abbrechen. Wenn die Bibliothek im Code direkt gebraucht wird, gehört sie in implementation.

Fehler Nr. 5: Den Block bearbeiten, ohne auf seine Lesbarkeit zu achten.
Gradle überlebt vielleicht das Zeilenchaos, aber ein Mensch – nicht immer. Wenn du nach der Bearbeitung nicht in 10 Sekunden erklären kannst, wo bei dir JSON ist, wo Logging ist und warum die Bibliotheken genau so aufgeteilt sind, beginnt der Block bereits gegen dich zu arbeiten.

1
Aufgabe
Java Server, Level 3, Lektion 3
Gesperrt
Akribisch gruppierter dependencies-Block
Akribisch gruppierter dependencies-Block
1
Aufgabe
Java Server, Level 3, Lektion 3
Gesperrt
Hinzufügen einer neuen Zeile in dependencies
Hinzufügen einer neuen Zeile in dependencies
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION