Skip to content

5.0.0: instance-based App, POST defaults to 200, JUnit 5 - #53

Merged
ghosthack merged 4 commits into
masterfrom
claude/vigilant-allen-k2k12x
Sep 27, 2026
Merged

ghosthack merged 4 commits into
masterfrom
claude/vigilant-allen-k2k12x

Conversation

@ghosthack

Copy link
Copy Markdown
Owner

Follow-up to #52. Breaking release: bumps the version to 5.0.0.

Summary

Instance-based App

  • Routes, the not-found handler and the embedded server now live in an App instance. Several apps can run in one JVM, and a test can build a fresh app instead of resetting global state.
  • The static Turismo.get() / start() / … API delegates to a shared default app (Turismo.app()), so existing code compiles and behaves as before.
  • Request/response helpers (param(), print(), json(), …) stay static and work inside any app's handlers. When one app dispatches to another from inside a handler, the outer request context is restored afterwards.
  • New Server(App, int) constructor; Server(int) serves the default app.

POST defaults to 200 (breaking)

  • post() and @POST no longer force 201; every route defaults to 200. Handlers call status(201) when they create something.

Tests: JUnit 4 → JUnit Jupiter 6.1.3

  • Jupiter 6.1.3 is the current release of the JUnit 5 programming model; the project already requires Java 21, so its Java 17 baseline is fine.
  • Converted all tests: lifecycle annotations, assertThrows instead of @Test(expected), and assertion messages moved to the last argument.
  • New AppTest: isolation between apps and the default app, per-app not-found and reset, nested dispatch, two apps serving on separate ports.

Version 5.0.0

  • pom.xml and README install snippets bumped to 5.0.0.
  • New README section, "Upgrading to 5.0", lists every breaking change since 4.0.0, including those merged in Refactor multipart parser and improve routing/JSON serialization #52:
    • POST default status
    • servlet 405 responses
    • encoded-slash matching
    • route validation
    • multipart UTF-8 default and 400/413 responses

Notes

  • This branch contains a merge of master because Refactor multipart parser and improve routing/JSON serialization #52 was squash-merged. The squashed commit's tree is identical to the original, so the diff against master contains only the changes above.
  • After merging, release by tagging v5.0.0 on master; the release workflow checks the tag against pom.xml.

Testing

  • mvn verify: 190 tests pass, javadoc builds, and 5.0.0 artifacts are produced.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Leqha458EwWbRT5xWiVuyg


Generated by Claude Code

Security:
- Exact routes were looked up by the decoded path, so /admin%2Fsecret
  reached the /admin/secret route. Skip exact lookup (and Allow
  reporting) when the raw path contains an encoded slash.

Multipart:
- Rewrite MultipartParser: read the body as it arrives up to the limit
  instead of reserving Content-Length bytes up front, parse part headers
  properly (any order/case, extra headers, missing Content-Type,
  preamble, transport padding, quoted params), accept chunked uploads.
- Oversized bodies throw the new ContentTooLargeException; a missing
  boundary or unsupported charset is a ParseException instead of an
  IllegalArgumentException. MultipartFilter answers 413 / 400 rather
  than a 500.
- Default charset is now UTF-8, matching what browsers send.

Router and server:
- Log unhandled handler errors via System.Logger before sending 500.
- Add Server.stop(Duration) / Turismo.stop(Duration) for graceful stop.
- Validate route() arguments (non-null, path starts with '/') and
  notFound(null).
- toJson supports Character, enums, records and every array type.
- PathPattern returns unmodifiable maps as documented.

Servlet resolvers:
- ListResolver/MapResolver serve HEAD from GET routes and answer
  wrong-method requests with 405 + Allow, like the embedded server.

Adds tests for all of the above, including the first multipart tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Leqha458EwWbRT5xWiVuyg
App:
- Routes, the not-found handler and the embedded server now live in an
  App instance, so several route sets can coexist in one JVM and tests
  can use a fresh app instead of resetting shared state.
- Turismo's static registration and server methods delegate to a shared
  default app (Turismo.app()), so existing code is unchanged. Request
  and response helpers stay static and work for whichever app serves
  the request; nested dispatch restores the outer request context.
- Server gains a Server(App, int) constructor; Server(int) serves the
  default app.

POST status (breaking):
- post() and @post no longer force 201; every route defaults to 200
  and handlers call status(201) when they create something.

Tests:
- Migrate from JUnit 4.13.2 to JUnit Jupiter 6.1.3 (the current
  JUnit 5 programming model): lifecycle annotations, assertThrows
  instead of @test(expected), message-last assertion arguments.
- Add AppTest covering isolation, per-app not-found/reset, nested
  dispatch and two apps serving on separate ports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Leqha458EwWbRT5xWiVuyg
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Leqha458EwWbRT5xWiVuyg
@ghosthack
ghosthack merged commit 6438897 into master Sep 27, 2026
6 checks passed
@ghosthack
ghosthack deleted the claude/vigilant-allen-k2k12x branch September 27, 2026 07:16
ghosthack pushed a commit that referenced this pull request Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants