Fachlicher Vertrag: unverändert zu erhalten
- Pfad, Statuscode, Content-Type und Response-Body bleiben vertragskonform.
- Container-spezifische Startlogik wird vom Controller getrennt.
- Statische Inhalte und API-Routen kollidieren nicht.
javax.servlet wird nachvollziehbar in Spring MVC auf jakarta.servlet überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.
| Dimension | Legacy | Modern | Migrationskonsequenz |
|---|---|---|---|
| Programmiermodell | Override | GetMapping, RestController, SpringBootApplication | Annotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen. |
| Abhängigkeiten | 3 direkte Dependencies | 3 direkte Dependencies | 3 neu, 3 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen. |
| Öffentliche API | 2 erkannte Methoden | 2 erkannte Methoden | Methoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag. |
| Datenmodell | class ServletLegacyApplication, class StatusServlet | class StatusController, class WebModernApplication | Feldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet. |
| Fehlerverhalten | Legacy-Exceptions und Rückgabewerte | explizitere Fach-/Framework-Fehlerabbildung | Fehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden. |
| Tests | Bestands- und Golden-Master-Tests | Unit-, Slice-, Contract- und Integrationstests | Der Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt. |
| Betrieb | Legacy-Start/Lifecycle | modernes Packaging, Health und externe Konfiguration | Reverse Proxy, Context Path, Graceful Shutdown und Management-Exposition prüfen. |
| Rollback | Legacy-Artefakt bleibt unverändert | Modern-Artefakt getrennt deploybar | Kein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein. |
container/API migration and endpoint compatibility
web slice, content type, health and malformed request tests
Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.
| Legacy-Rolle / Datei | Modern-Rolle / Datei | Bedeutung |
|---|---|---|
| StatusServlet.java | StatusController.java | Servlet Adapter wird Spring MVC Controller. |
| ServletLegacyApplication.java | WebModernApplication.java | Embedded Jetty Bootstrap wird Spring Boot. |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| ServletLegacyApplication.java | class ServletLegacyApplication | — | void main(String[] args) | — | 21 |
| StatusServlet.java | class StatusServlet | Override | void doGet(HttpServletRequest request, HttpServletResponse response) | Front Controller (kleine Demonstration) | 21 |
| Datei | Typ | Annotationen | öffentliche API | Pattern | Zeilen |
|---|---|---|---|---|---|
| StatusController.java | class StatusController | GetMapping, RestController | Map<String, String> status() | Front Controller + MVC Controller | 15 |
| WebModernApplication.java | class WebModernApplication | SpringBootApplication | void main(String[] args) | — | 11 |
| Status | Dependency | Version | Scope | Prüfung |
|---|---|---|---|---|
| ENTFERNT | org.eclipse.jetty:jetty-server | ${jetty10.version} | compile | Legacy-Laufzeit entfällt oder wird durch Plattform/BOM ersetzt. |
| ENTFERNT | org.eclipse.jetty:jetty-servlet | ${jetty10.version} | compile | Legacy-Laufzeit entfällt oder wird durch Plattform/BOM ersetzt. |
| ENTFERNT | org.junit.jupiter:junit-jupiter | BOM/Parent | test | Legacy-Laufzeit entfällt oder wird durch Plattform/BOM ersetzt. |
| NEU | org.springframework.boot:spring-boot-starter-actuator | BOM/Parent | compile | Neue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen. |
| NEU | org.springframework.boot:spring-boot-starter-test | BOM/Parent | test | Neue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen. |
| NEU | org.springframework.boot:spring-boot-starter-web | BOM/Parent | compile | Neue Laufzeit-/Testabhängigkeit; transitiv, lizenz- und security-seitig prüfen. |
Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.
Migrationsbedeutung: Servlet Adapter wird Spring MVC Controller.
projects/09-servlet-web/legacy/src/main/java/at/aydin/lab/web/legacy/StatusServlet.java
package at.aydin.lab.web.legacy;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setStatus(200);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(statusJson());
}
// Design Pattern: Front Controller (kleine Demonstration)
// Zweck: Ein zentraler Servlet-Endpunkt verarbeitet den HTTP-Aufruf.
static String statusJson() {
return "{\"status\":\"UP\",\"stack\":\"javax.servlet\"}";
}
}
projects/09-servlet-web/modern/src/main/java/at/aydin/lab/web/modern/StatusController.java
package at.aydin.lab.web.modern;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
// Design Pattern: Front Controller + MVC Controller
// Zweck: Spring MVC übernimmt Routing, Konvertierung und HTTP-Infrastruktur.
public class StatusController {
@GetMapping("/status")
public Map<String, String> status() {
return Map.of("status", "UP", "stack", "Spring MVC / jakarta.servlet");
}
}
--- StatusServlet.java
+++ StatusController.java
@@ -1,21 +1,15 @@
-package at.aydin.lab.web.legacy;
+package at.aydin.lab.web.modern;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.Map;
-public class StatusServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
- response.setStatus(200);
- response.setContentType("application/json;charset=UTF-8");
- response.getWriter().write(statusJson());
- }
-
- // Design Pattern: Front Controller (kleine Demonstration)
- // Zweck: Ein zentraler Servlet-Endpunkt verarbeitet den HTTP-Aufruf.
- static String statusJson() {
- return "{\"status\":\"UP\",\"stack\":\"javax.servlet\"}";
+@RestController
+// Design Pattern: Front Controller + MVC Controller
+// Zweck: Spring MVC übernimmt Routing, Konvertierung und HTTP-Infrastruktur.
+public class StatusController {
+ @GetMapping("/status")
+ public Map<String, String> status() {
+ return Map.of("status", "UP", "stack", "Spring MVC / jakarta.servlet");
}
}
Migrationsbedeutung: Embedded Jetty Bootstrap wird Spring Boot.
projects/09-servlet-web/legacy/src/main/java/at/aydin/lab/web/legacy/ServletLegacyApplication.java
package at.aydin.lab.web.legacy;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public final class ServletLegacyApplication {
private ServletLegacyApplication() {
}
public static void main(String[] args) throws Exception {
Server server = new Server(8083);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(new ServletHolder(new StatusServlet()), "/status");
server.setHandler(context);
server.start();
System.out.println("Legacy Servlet: http://localhost:8083/status");
server.join();
}
}
projects/09-servlet-web/modern/src/main/java/at/aydin/lab/web/modern/WebModernApplication.java
package at.aydin.lab.web.modern;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebModernApplication {
public static void main(String[] args) {
SpringApplication.run(WebModernApplication.class, args);
}
}
--- ServletLegacyApplication.java
+++ WebModernApplication.java
@@ -1,21 +1,11 @@
-package at.aydin.lab.web.legacy;
+package at.aydin.lab.web.modern;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
-public final class ServletLegacyApplication {
- private ServletLegacyApplication() {
- }
-
- public static void main(String[] args) throws Exception {
- Server server = new Server(8083);
- ServletContextHandler context = new ServletContextHandler();
- context.setContextPath("/");
- context.addServlet(new ServletHolder(new StatusServlet()), "/status");
- server.setHandler(context);
- server.start();
- System.out.println("Legacy Servlet: http://localhost:8083/status");
- server.join();
+@SpringBootApplication
+public class WebModernApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(WebModernApplication.class, args);
}
}
| ID | Ebene | Prüfung | erforderlicher Nachweis |
|---|---|---|---|
| 09-SERVLET-WEB-A01 | Integration/Contract | Health-/Status-Antwort ist semantisch identisch. | Automatisierter Test und CI-Protokoll |
| 09-SERVLET-WEB-A02 | Integration/Contract | Content-Type und Encoding stimmen. | Automatisierter Test und CI-Protokoll |
| 09-SERVLET-WEB-A03 | Integration/Contract | Unbekannte Pfade liefern definiertes 404-Verhalten. | Automatisierter Test und CI-Protokoll |
| 09-SERVLET-WEB-A04 | Integration/Contract | Keine unbeabsichtigten Management-Endpunkte sind extern. | Automatisierter Test und CI-Protokoll |
| 09-SERVLET-WEB-A05 | Integration/Contract | Graceful Shutdown funktioniert. | Automatisierter Test und CI-Protokoll |
| 09-SERVLET-WEB-T01 | Unit | Fachlogik ohne Container oder externen Dienst testen. | Unit-Test |
| 09-SERVLET-WEB-T02 | Regression | Legacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen. | Vergleichsreport |
| 09-SERVLET-WEB-T03 | Negative | Fehlerhafte, leere und grenzwertige Eingaben prüfen. | Negativtest |
| 09-SERVLET-WEB-T04 | Operations | Start, Health, Shutdown und Konfigurationsfehler prüfen. | Deployment-/Startprotokoll |
| 09-SERVLET-WEB-F01 | Fokus | web slice, content type, health and malformed request tests | Modulspezifischer Testreport |
| Risiko | Auswirkung | Gegenmaßnahme | Gate |
|---|---|---|---|
| container/API migration and endpoint compatibility | NIEDRIG | web slice, content type, health and malformed request tests | vor Cutover |
| Neue Framework-/Library-Laufzeitabhängigkeiten | MITTEL | SBOM, Lizenz-, CVE- und transitive Dependency-Prüfung im Online-Build | vor Release |
| Legacy-Verhalten war implizit an entfernte Library gekoppelt | MITTEL | Contract-/Golden-Master-Tests und gezielte Fehlerpfade | vor Abschaltung |
| Seite | Ressource | Zeilen |
|---|---|---|
| Modern | modern/src/main/resources/application.properties | 2 |
| Modern | modern/src/main/resources/static/index.html | 1 |
Load Balancer oder Reverse Proxy kann wieder auf Jetty zeigen; der Response Contract bleibt dabei unverändert.