Showing preview only (1,774K chars total). Download the full file or copy to clipboard to get everything.
Repository: javalin/javalin
Branch: master
Commit: fc424d1344d3
Files: 491
Total size: 1.6 MB
Directory structure:
gitextract_bkbr0xf4/
├── .editorconfig
├── .github/
│ ├── README.md
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── cleanup-performance-preview.yml
│ ├── main.yml
│ ├── publish-snapshots.yml
│ └── test-performance-command.yml
├── .gitignore
├── .mvn/
│ └── wrapper/
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── README.md
├── jacoco-coverage-report/
│ ├── README.md
│ └── pom.xml
├── javalin/
│ ├── module-info.java
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── io/
│ │ └── javalin/
│ │ ├── Javalin.java
│ │ ├── apibuilder/
│ │ │ ├── ApiBuilder.java
│ │ │ ├── CrudHandler.kt
│ │ │ └── EndpointGroup.java
│ │ ├── compression/
│ │ │ ├── Brotli.kt
│ │ │ ├── Brotli4jCompressor.kt
│ │ │ ├── CompressedStream.kt
│ │ │ ├── CompressionStrategy.kt
│ │ │ ├── CompressionType.kt
│ │ │ ├── Compressor.kt
│ │ │ ├── Gzip.kt
│ │ │ ├── GzipCompressor.kt
│ │ │ ├── Zstd.kt
│ │ │ └── ZstdCompressor.kt
│ │ ├── config/
│ │ │ ├── AppDataManager.kt
│ │ │ ├── BundledPluginsConfig.kt
│ │ │ ├── ConcurrencyConfig.kt
│ │ │ ├── ContextResolverConfig.kt
│ │ │ ├── EventConfig.kt
│ │ │ ├── HttpConfig.kt
│ │ │ ├── JavalinConfig.kt
│ │ │ ├── JavalinState.kt
│ │ │ ├── JettyConfig.kt
│ │ │ ├── JettyInternalConfig.kt
│ │ │ ├── MultipartConfig.kt
│ │ │ ├── RequestLoggerConfig.kt
│ │ │ ├── RouterConfig.kt
│ │ │ ├── RoutesConfig.kt
│ │ │ ├── SpaRootConfig.kt
│ │ │ ├── StartupConfig.kt
│ │ │ ├── StaticFilesConfig.kt
│ │ │ └── ValidationConfig.kt
│ │ ├── event/
│ │ │ ├── EventManager.kt
│ │ │ └── LifecycleEventListener.kt
│ │ ├── http/
│ │ │ ├── ContentType.kt
│ │ │ ├── Context.kt
│ │ │ ├── Cookie.kt
│ │ │ ├── ExceptionHandler.java
│ │ │ ├── Handler.java
│ │ │ ├── HandlerType.java
│ │ │ ├── Header.kt
│ │ │ ├── HttpResponseException.kt
│ │ │ ├── HttpStatus.kt
│ │ │ ├── RequestLogger.java
│ │ │ ├── SinglePageHandler.kt
│ │ │ ├── UploadedFile.kt
│ │ │ ├── servlet/
│ │ │ │ ├── DefaultTasks.kt
│ │ │ │ ├── JavalinServlet.kt
│ │ │ │ ├── JavalinServletContext.kt
│ │ │ │ ├── JavalinServletRequest.kt
│ │ │ │ ├── JavalinWsServletContext.kt
│ │ │ │ ├── MaxRequestSize.kt
│ │ │ │ ├── ServletEntry.kt
│ │ │ │ └── Task.kt
│ │ │ ├── sse/
│ │ │ │ ├── Emitter.kt
│ │ │ │ ├── SseClient.kt
│ │ │ │ └── SseHandler.kt
│ │ │ ├── staticfiles/
│ │ │ │ ├── JavalinStaticResourceHandler.kt
│ │ │ │ ├── ResourceHandler.java
│ │ │ │ ├── StaticFileConfig.kt
│ │ │ │ ├── StaticFileHandler.kt
│ │ │ │ └── StaticResource.kt
│ │ │ └── util/
│ │ │ ├── AsyncUtil.kt
│ │ │ ├── CookieStore.kt
│ │ │ ├── ETagGenerator.kt
│ │ │ ├── JsonEscapeUtil.kt
│ │ │ ├── MethodNotAllowedUtil.kt
│ │ │ ├── MultipartUtil.kt
│ │ │ └── SeekableWriter.kt
│ │ ├── jetty/
│ │ │ ├── JavalinJettyServlet.kt
│ │ │ ├── JettyPrecompressingResourceHandler.kt
│ │ │ ├── JettyResourceHandler.kt
│ │ │ ├── JettyServer.kt
│ │ │ └── JettyUtil.kt
│ │ ├── json/
│ │ │ ├── JavalinGson.kt
│ │ │ ├── JavalinJackson.kt
│ │ │ ├── JsonMapper.kt
│ │ │ └── PipedStreamUtil.kt
│ │ ├── plugin/
│ │ │ ├── PluginApi.kt
│ │ │ ├── PluginExceptions.kt
│ │ │ ├── PluginManager.kt
│ │ │ └── bundled/
│ │ │ ├── BasicAuthPlugin.kt
│ │ │ ├── CorsPlugin.kt
│ │ │ ├── CorsUtils.kt
│ │ │ ├── DevLoggerPlugin.kt
│ │ │ ├── GlobalHeadersPlugin.kt
│ │ │ ├── HttpAllowedMethodsPlugin.kt
│ │ │ ├── JavalinVuePlugin.kt
│ │ │ ├── RateLimitPlugin.kt
│ │ │ ├── RedirectToLowercasePathPlugin.kt
│ │ │ ├── RouteOverviewPlugin.kt
│ │ │ ├── RouteOverviewUtil.kt
│ │ │ └── SslRedirectPlugin.kt
│ │ ├── rendering/
│ │ │ └── FileRenderer.kt
│ │ ├── router/
│ │ │ ├── Endpoint.kt
│ │ │ ├── Endpoints.kt
│ │ │ ├── HandlerWrapper.kt
│ │ │ ├── InternalRouter.kt
│ │ │ ├── JavalinDefaultRoutingApi.kt
│ │ │ ├── ParsedEndpoint.kt
│ │ │ ├── error/
│ │ │ │ └── ErrorMapper.kt
│ │ │ ├── exception/
│ │ │ │ ├── ExceptionMapper.kt
│ │ │ │ ├── HttpResponseExceptionMapper.kt
│ │ │ │ └── JavaLangErrorHandler.kt
│ │ │ └── matcher/
│ │ │ ├── ParserExceptions.kt
│ │ │ ├── ParserState.kt
│ │ │ ├── PathMatcher.kt
│ │ │ ├── PathParser.kt
│ │ │ ├── PathSegment.kt
│ │ │ └── RoutingRegexes.kt
│ │ ├── security/
│ │ │ ├── BasicAuthCredentials.kt
│ │ │ └── RouteRole.kt
│ │ ├── util/
│ │ │ ├── ConcurrencyUtil.kt
│ │ │ ├── FileUtil.kt
│ │ │ ├── JavalinExceptions.kt
│ │ │ ├── JavalinLogger.kt
│ │ │ ├── OptionalDependency.kt
│ │ │ ├── ReflectionUtil.kt
│ │ │ ├── Util.kt
│ │ │ ├── function/
│ │ │ │ ├── ThrowingConsumer.java
│ │ │ │ └── ThrowingRunnable.java
│ │ │ └── legacy/
│ │ │ └── LegacyAccessManager.kt
│ │ ├── validation/
│ │ │ ├── BodyValidator.kt
│ │ │ ├── Validation.kt
│ │ │ └── Validator.kt
│ │ ├── vue/
│ │ │ ├── JavalinVueConfig.kt
│ │ │ ├── LoadableData.kt
│ │ │ ├── VueComponent.kt
│ │ │ ├── VueDependencyResolver.java
│ │ │ ├── VueFileInliner.kt
│ │ │ ├── VueHandler.kt
│ │ │ ├── VuePathMaster.kt
│ │ │ ├── VueRenderer.kt
│ │ │ └── VueStateRenderer.kt
│ │ └── websocket/
│ │ ├── WsAutomaticPing.kt
│ │ ├── WsCloseStatus.kt
│ │ ├── WsConfig.java
│ │ ├── WsConnection.kt
│ │ ├── WsContext.kt
│ │ ├── WsExceptionHandler.java
│ │ ├── WsExceptionMapper.kt
│ │ ├── WsHandlers.kt
│ │ ├── WsPathMatcher.kt
│ │ ├── WsRouter.kt
│ │ └── WsUpgradeLogger.java
│ └── test/
│ ├── external/
│ │ ├── html.html
│ │ └── txt.txt
│ ├── java/
│ │ └── io/
│ │ └── javalin/
│ │ ├── LargeSeekableInput.kt
│ │ ├── TestApiBuilder.kt
│ │ ├── TestApiBuilderWebSocket.java
│ │ ├── TestAppData.kt
│ │ ├── TestBeforeAfterMatched.kt
│ │ ├── TestBeforeMatched.kt
│ │ ├── TestBodyReading.kt
│ │ ├── TestClose.kt
│ │ ├── TestClose_Java.java
│ │ ├── TestCompression.kt
│ │ ├── TestConcurrencyUtil.kt
│ │ ├── TestConfiguration.kt
│ │ ├── TestConfigureServletContextHandler.kt
│ │ ├── TestContextHandlerType.java
│ │ ├── TestContextPath.kt
│ │ ├── TestContextRouteRoles.kt
│ │ ├── TestCookie.kt
│ │ ├── TestCookieStore.kt
│ │ ├── TestCors.kt
│ │ ├── TestCorsUtils.kt
│ │ ├── TestCustomJetty.kt
│ │ ├── TestCustomJettyHttpConfiguration.kt
│ │ ├── TestCustomRequestLifecycle.kt
│ │ ├── TestDependencyUtil.kt
│ │ ├── TestEncoding.kt
│ │ ├── TestEndpoint.kt
│ │ ├── TestErrorMapper.kt
│ │ ├── TestEtags.kt
│ │ ├── TestEventManager.kt
│ │ ├── TestExceptionMapper.kt
│ │ ├── TestFilters.kt
│ │ ├── TestFuture.kt
│ │ ├── TestGlobalGlobalHeaderConfigPlugin.kt
│ │ ├── TestGracefulShutdown.java
│ │ ├── TestHandlerWrapper.kt
│ │ ├── TestHttpAllowedMethodsPlugin.kt
│ │ ├── TestHttpResponseExceptions.kt
│ │ ├── TestJavalinGson.kt
│ │ ├── TestJavalinInstanceAndConfigApi.kt
│ │ ├── TestJavalinInstanceAndConfigApi_Java.java
│ │ ├── TestJavalinJackson.kt
│ │ ├── TestJson.kt
│ │ ├── TestJsonMapper.kt
│ │ ├── TestJsonMapperExtensions.kt
│ │ ├── TestLegacyAccessManager.kt
│ │ ├── TestLifecycleEvents.kt
│ │ ├── TestLogging.kt
│ │ ├── TestMaxRequestSize.kt
│ │ ├── TestMethodNotAllowed.kt
│ │ ├── TestMocking.kt
│ │ ├── TestMultipartForms.kt
│ │ ├── TestMultipleSlashes.kt
│ │ ├── TestPlugins.kt
│ │ ├── TestPublicApi_Java.java
│ │ ├── TestRedirectToLowercasePathPlugin.kt
│ │ ├── TestRendering.kt
│ │ ├── TestRequest.kt
│ │ ├── TestRequest_Java.java
│ │ ├── TestResponse.kt
│ │ ├── TestRoutesConfig.kt
│ │ ├── TestRouting.kt
│ │ ├── TestServerHeader.kt
│ │ ├── TestSse.kt
│ │ ├── TestSslRedirectPlugin.kt
│ │ ├── TestTrailingSlashes.kt
│ │ ├── TestUnixSocketConnector.kt
│ │ ├── TestUnsafeStateAccess.kt
│ │ ├── TestUtil.kt
│ │ ├── TestValidation.kt
│ │ ├── TestValidation_Java.java
│ │ ├── TestWebBrowser.kt
│ │ ├── examples/
│ │ │ ├── CopilotInstructionsPatternValidation.java
│ │ │ ├── FileUploadExample.java
│ │ │ ├── HelloWorld.java
│ │ │ ├── HelloWorldApi.java
│ │ │ ├── HelloWorldAsync.java
│ │ │ ├── HelloWorldAuth.java
│ │ │ ├── HelloWorldBasicAuth.java
│ │ │ ├── HelloWorldCors.java
│ │ │ ├── HelloWorldCustomJsonMapper.java
│ │ │ ├── HelloWorldFuture.java
│ │ │ ├── HelloWorldPlugin.java
│ │ │ ├── HelloWorldSecure.java
│ │ │ ├── HelloWorldServlet.java
│ │ │ ├── HelloWorldSse.java
│ │ │ ├── HelloWorldStaticFiles.java
│ │ │ ├── HelloWorldStaticFiles_external.java
│ │ │ ├── HelloWorldStaticFiles_linked.java
│ │ │ └── HelloWorldWebSockets.java
│ │ ├── http/
│ │ │ ├── ContentTypeTest.kt
│ │ │ ├── HttpResponseExceptionTest.kt
│ │ │ ├── HttpStatusCodeTest.kt
│ │ │ └── TestCustomHttpMethods.kt
│ │ ├── javalinvue/
│ │ │ ├── TestJavalinVue.kt
│ │ │ ├── TestJavalinVueBrowser.kt
│ │ │ ├── TestJavalinVueHandler.java
│ │ │ ├── TestJavalinVueResolution.java
│ │ │ └── VueTestUtil.kt
│ │ ├── performance/
│ │ │ ├── PathMatcherBenchmark.java
│ │ │ ├── PerformanceBenchmarkSuite.java
│ │ │ └── SimpleAsyncTest.java
│ │ ├── routeoverview/
│ │ │ ├── TestRouteOverviewInJava.java
│ │ │ ├── TestRouteOverviewInKotlin.kt
│ │ │ ├── TestRouteOverviewPlugin.kt
│ │ │ └── VisualTest.java
│ │ ├── staticfiles/
│ │ │ ├── StaticFilesTestUtil.kt
│ │ │ ├── TestSinglePageMode.kt
│ │ │ ├── TestStaticDirectorySlash.kt
│ │ │ ├── TestStaticFileAccess.kt
│ │ │ ├── TestStaticFiles.kt
│ │ │ ├── TestStaticFilesEdgeCases.kt
│ │ │ ├── TestStaticFilesPathTraversal.kt
│ │ │ └── TestStaticFilesPrecompressor.kt
│ │ ├── testing/
│ │ │ ├── FasterJacksonMapper.kt
│ │ │ ├── HttpUtil.kt
│ │ │ ├── JavalinTestUtil.java
│ │ │ ├── NonSerializableObject.java
│ │ │ ├── RunResult.java
│ │ │ ├── SerializableObject.java
│ │ │ ├── TestDependency.kt
│ │ │ ├── TestEnvironment.kt
│ │ │ ├── TestServlet.java
│ │ │ ├── TestUtil.java
│ │ │ ├── ThrowingBiConsumer.java
│ │ │ ├── TypedException.java
│ │ │ ├── UploadInfo.kt
│ │ │ └── WebDriverUtil.kt
│ │ └── websocket/
│ │ ├── TestWebSocket.kt
│ │ ├── TestWebSocketHttp2.kt
│ │ ├── TestWsBeforeAfter.kt
│ │ ├── TestWsContext.kt
│ │ ├── TestWsException.kt
│ │ ├── TestWsLogging.kt
│ │ ├── TestWsRouting.kt
│ │ ├── TestWsUpgrade.kt
│ │ └── WebSocketTestHelpers.kt
│ ├── kotlin/
│ │ └── io/
│ │ └── javalin/
│ │ ├── TestRateLimitPlugin.kt
│ │ └── examples/
│ │ ├── AdvancedServerSentEvent.kt
│ │ ├── FileUploadExample.kt
│ │ ├── HelloWorld.kt
│ │ ├── HelloWorldApi.kt
│ │ ├── HelloWorldAsync.kt
│ │ ├── HelloWorldAuth.kt
│ │ ├── HelloWorldCors.kt
│ │ ├── HelloWorldCustomJsonMapper.kt
│ │ ├── HelloWorldImages.kt
│ │ ├── HelloWorldPlugin.kt
│ │ ├── HelloWorldSecure.kt
│ │ ├── HelloWorldSse.kt
│ │ ├── HelloWorldStaticFiles.kt
│ │ ├── HelloWorldStaticFiles_external.kt
│ │ ├── HelloWorldWebSockets.kt
│ │ └── KotlinExample.kt
│ └── resources/
│ ├── keystore.jks
│ ├── markdown/
│ │ └── test.md
│ ├── public/
│ │ ├── assets/
│ │ │ └── filtered-styles.css
│ │ ├── file
│ │ ├── file.javalin
│ │ ├── html.html
│ │ ├── module.mjs
│ │ ├── protected/
│ │ │ └── secret.html
│ │ ├── readme.md.br
│ │ ├── script.js
│ │ ├── sse/
│ │ │ └── sse-example.html
│ │ ├── styles.css
│ │ ├── subdir/
│ │ │ └── index.html
│ │ └── subpage/
│ │ └── index.html
│ ├── public2/
│ │ └── secret.txt
│ ├── upload-test/
│ │ └── text.txt
│ └── vue/
│ ├── dependency-1-foo.vue
│ ├── dependency-1.vue
│ ├── dependency-123.vue
│ ├── dependency-one-3.vue
│ ├── dependency-one.vue
│ ├── dependency-two-3.vue
│ ├── dependency-two.vue
│ ├── layout.html
│ ├── multi-dependency.vue
│ ├── nested-dependency.vue
│ ├── scripts-dev.js
│ ├── scripts-not-dev.js
│ ├── scripts.js
│ ├── test-component-3.vue
│ ├── test-component.vue
│ ├── view-multiline-dependency.vue
│ ├── view-nested-dependency.vue
│ ├── view-number-dependency.vue
│ ├── view-one-3.vue
│ ├── view-one.vue
│ ├── view-three.vue
│ └── view-two.vue
├── javalin-bom/
│ └── pom.xml
├── javalin-bundle/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── resources/
│ └── logback.xml
├── javalin-micrometer/
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── kotlin/
│ │ │ └── io/
│ │ │ └── javalin/
│ │ │ └── micrometer/
│ │ │ └── MicrometerPlugin.kt
│ │ └── module-info.java
│ └── test/
│ └── kotlin/
│ └── io/
│ └── javalin/
│ └── micrometer/
│ └── MicrometerPluginTest.kt
├── javalin-ssl/
│ ├── README.md
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── kotlin/
│ │ │ └── io/
│ │ │ └── javalin/
│ │ │ └── community/
│ │ │ └── ssl/
│ │ │ ├── SslConfig.kt
│ │ │ ├── SslConfigException.kt
│ │ │ ├── SslPlugin.kt
│ │ │ ├── TlsConfig.kt
│ │ │ ├── TrustConfig.kt
│ │ │ └── util/
│ │ │ ├── ConnectorFactory.kt
│ │ │ └── SSLUtils.kt
│ │ └── module-info.java
│ └── test/
│ ├── java/
│ │ └── io/
│ │ └── javalin/
│ │ └── community/
│ │ └── ssl/
│ │ └── JavaAPITests.java
│ ├── kotlin/
│ │ └── io/
│ │ └── javalin/
│ │ └── community/
│ │ └── ssl/
│ │ ├── APITests.kt
│ │ ├── IntegrationTestClass.kt
│ │ ├── KeystoreLoadingTests.kt
│ │ ├── PemLoadingTests.kt
│ │ ├── SslConfigExceptionTest.kt
│ │ ├── SslConfigTests.kt
│ │ ├── SslPluginTest.kt
│ │ ├── TlsConfigTest.kt
│ │ ├── TrustConfigTests.kt
│ │ └── certs/
│ │ ├── CertificateAuthorityTests.kt
│ │ ├── Client.kt
│ │ └── Server.kt
│ └── resources/
│ ├── ca/
│ │ ├── client-fullchain.cer
│ │ ├── client-nochain.cer
│ │ ├── client.key
│ │ ├── keystores/
│ │ │ ├── client.p12
│ │ │ ├── issuer-ca.p12
│ │ │ ├── root-ca.p12
│ │ │ └── server.p12
│ │ ├── root-ca.cer
│ │ ├── server.cer
│ │ └── server.key
│ ├── client/
│ │ ├── cert.der
│ │ ├── cert.jks
│ │ ├── cert.p12
│ │ ├── cert.p7b
│ │ ├── cert.pem
│ │ └── key.pem
│ └── server/
│ ├── cert.crt
│ ├── encrypted.key
│ ├── keystore.jks
│ ├── keystore.p12
│ ├── malformed.jks
│ ├── malformed.p12
│ ├── norway.jks
│ ├── norway.p12
│ ├── passwordless.key
│ └── wrong.pem
├── javalin-testtools/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── io/
│ │ └── javalin/
│ │ └── testtools/
│ │ ├── HttpClient.kt
│ │ ├── JavalinTest.kt
│ │ ├── TestCase.java
│ │ └── TestTool.kt
│ └── test/
│ ├── java/
│ │ └── io/
│ │ └── javalin/
│ │ └── testtools/
│ │ ├── JavaApp.java
│ │ ├── JavaTest.java
│ │ └── TestCookieIssue.java
│ └── kotlin/
│ └── io/
│ └── javalin/
│ └── testtools/
│ ├── KotlinApp.kt
│ ├── KotlinTest.kt
│ └── TestCookieIssue.kt
├── javalin-utils/
│ ├── javalin-context-mock/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── io/
│ │ │ └── javalin/
│ │ │ └── mock/
│ │ │ ├── Body.kt
│ │ │ ├── ContextMock.kt
│ │ │ ├── ContextMockConfig.kt
│ │ │ ├── ContextMockConfigurer.kt
│ │ │ └── servlet/
│ │ │ ├── InMemoryHttpServletRequest.kt
│ │ │ ├── InMemoryHttpServletResponse.kt
│ │ │ ├── InMemoryHttpSession.kt
│ │ │ └── InMemoryPart.kt
│ │ └── test/
│ │ └── java/
│ │ └── io/
│ │ └── javalin/
│ │ └── mock/
│ │ └── TestMockContext.kt
│ ├── javalin-rendering/
│ │ ├── javalin-rendering-commonmark/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── markdown/
│ │ │ │ └── Commonmark.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestCommonmark.kt
│ │ │ └── resources/
│ │ │ └── markdown/
│ │ │ └── test.md
│ │ ├── javalin-rendering-freemarker/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ ├── JavalinFreemarker.kt
│ │ │ │ └── TemplateUtil.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestFreemarker.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ ├── freemarker/
│ │ │ │ ├── test-with-base.ftl
│ │ │ │ └── test.ftl
│ │ │ ├── test-with-base.ftl
│ │ │ └── test.ftl
│ │ ├── javalin-rendering-handlebars/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ └── JavalinHandlebars.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestHandlebars.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ └── handlebars/
│ │ │ └── test.hbs
│ │ ├── javalin-rendering-jte/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ └── JavalinJte.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestJte.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ └── jte/
│ │ │ ├── test-variable.jte
│ │ │ └── test.jte
│ │ ├── javalin-rendering-mustache/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ ├── JavalinMustache.kt
│ │ │ │ └── TemplateUtil.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestMustache.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ ├── mustache/
│ │ │ │ └── test.mustache
│ │ │ └── test.mustache
│ │ ├── javalin-rendering-pebble/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ ├── JavalinPebble.kt
│ │ │ │ └── TemplateUtil.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestPebble.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ ├── pebble/
│ │ │ │ ├── test-empty-context-map.peb
│ │ │ │ └── test.peb
│ │ │ ├── test-empty-context-map.peb
│ │ │ └── test.peb
│ │ ├── javalin-rendering-thymeleaf/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ ├── JavalinThymeleaf.kt
│ │ │ │ └── TemplateUtil.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestThymeleaf.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ ├── test.html
│ │ │ ├── testUrls.html
│ │ │ └── thymeleaf/
│ │ │ ├── test.html
│ │ │ └── testUrls.html
│ │ ├── javalin-rendering-velocity/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ ├── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── rendering/
│ │ │ │ └── template/
│ │ │ │ ├── JavalinVelocity.kt
│ │ │ │ └── TemplateUtil.kt
│ │ │ └── test/
│ │ │ ├── java/
│ │ │ │ └── io/
│ │ │ │ └── javalin/
│ │ │ │ └── TestVelocity.kt
│ │ │ └── resources/
│ │ │ └── templates/
│ │ │ ├── test-set.vm
│ │ │ ├── test.vm
│ │ │ └── velocity/
│ │ │ ├── test-set.vm
│ │ │ └── test.vm
│ │ └── pom.xml
│ ├── pom.properties
│ └── pom.xml
├── mvnw
├── mvnw.cmd
├── pom.properties
└── pom.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 200
[*.java]
ij_java_names_count_to_use_import_on_demand = 999
ij_java_use_single_class_imports = true
[*.kt]
ij_kotlin_name_count_to_use_star_import = 999
ij_kotlin_name_count_to_use_star_import_for_members = 999
[*.md]
trim_trailing_whitespace = false
[*.{js,css,html}]
insert_final_newline = false
[*.{yml,yaml,json}]
indent_size = 2
================================================
FILE: .github/README.md
================================================
<a name="readme-top"></a>
<div align="center">
<!--Logo-->
<a href="https://github.com/javalin/javalin">
<img src="img/javalin.png" alt="Logo" width="70%">
</a>
<!--Title-->
<h3 align="center">A simple web framework for Java and Kotlin</h3>
<h2>
<a href="https://javalin.io/documentation"><strong>View the documentation →</strong></a>
<br>
<br>
</h2>
<br>
<!--License badge-->
<a href="https://github.com/javalin/javalin/blob/master/LICENSE">
<img alt="Static Badge" src="https://img.shields.io/badge/License-Apache_2.0-blue">
</a>
<!--Maven central stable version badge-->
<a href="https://central.sonatype.com/artifact/io.javalin/javalin">
<img alt="Stable Version" src="https://img.shields.io/maven-central/v/io.javalin/javalin?label=stable">
</a>
<!--Reposilite snapshot version badge-->
<a href="https://repo.reposilite.com/#/snapshots/io/javalin/javalin">
<img alt="Snapshot Version" src="https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Frepo.reposilite.com%2Fsnapshots%2Fio%2Fjavalin%2Fjavalin%2Fmaven-metadata.xml&label=snapshot">
</a>
<!--Discord badge-->
<a href="https://discord.gg/sgak4e5NKv">
<img alt="Discord Link" src="https://img.shields.io/discord/804862058528505896?label=discord%20chat&logo=discord&logoColor=white">
</a>
<!--Build Status badge-->
<a href="https://github.com/javalin/javalin/actions/workflows/main.yml">
<img alt="Build Status" src="https://github.com/javalin/javalin/actions/workflows/main.yml/badge.svg"/>
</a>
<!--Codecov badge-->
<a href="https://codecov.io/gh/javalin/javalin" >
<img src="https://codecov.io/gh/javalin/javalin/graph/badge.svg?token=3L3CvpyMPI"/>
</a>
</div>
#
Javalin is a very lightweight web framework for Kotlin and Java which supports WebSockets, HTTP2 and async requests.
Javalin’s main goals are simplicity, a great developer experience, and first class interoperability between Kotlin and Java.
Javalin is more of a library than a framework. Some key points:
* You don't need to extend anything
* There are no @Annotations
* There is no reflection
* There is no other magic; just code.
#### General information
* The project webpage is [javalin.io](https://javalin.io) (the source is at [javalin/javalin.github.io](https://github.com/javalin/javalin.github.io)).
* Read the documentation on: [javalin.io/documentation](https://javalin.io/documentation)
* A summary of the license can be found at [TLDR Legal](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0))
* [Interesting issues](https://github.com/javalin/javalin/issues?q=is%3Aissue+label%3AINFO)
#### Community
We have a very active [Discord](https://discord.gg/sgak4e5NKv) server where you can get help quickly.
Contributions are very welcome, you can read more about contributing in our guide:
[CONTRIBUTING](https://github.com/javalin/javalin/contribute)
Please consider [:heart: Sponsoring](https://github.com/sponsors/tipsy) or starring Javalin if you want to support the project.
## Quickstart
### Add dependency
#### Maven
```xml
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>7.1.0</version>
</dependency>
```
#### Gradle
```kotlin
implementation("io.javalin:javalin:7.1.0")
```
### Start programming (Java)
```java
import io.javalin.Javalin;
public class HelloWorld {
public static void main(String[] args) {
var app = Javalin.create(config -> {
config.routes.get("/", ctx -> ctx.result("Hello World"));
}).start(7070);
}
}
```
### Start programming (Kotlin)
```kotlin
import io.javalin.Javalin
fun main() {
val app = Javalin.create { config ->
config.routes.get("/") { it.result("Hello World") }
}.start(7070)
}
```
## Examples
This section contains a few examples, mostly just extracted from the [docs](https://javalin.io/documentation).
All examples are in Kotlin, but you can find them in Java in the documentation (it's just syntax changes).
You can find more examples in the [javalin-samples](https://github.com/javalin/javalin-samples) repository.
### Api structure and server config
```kotlin
import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.*
fun main() {
val app = Javalin.create { config ->
config.concurrency.useVirtualThreads = true
config.http.asyncTimeout = 10_000L
config.staticFiles.add("/public")
config.staticFiles.enableWebjars()
config.routes.apiBuilder {
path("/users") {
get(UserController::getAll)
post(UserController::create)
path("/{userId}") {
get(UserController::getOne)
patch(UserController::update)
delete(UserController::delete)
}
ws("/events", userController::webSocketEvents)
}
}
}.start(7070)
}
```
### WebSockets
```kotlin
config.routes.ws("/websocket/{path}") { ws ->
ws.onConnect { ctx -> println("Connected") }
ws.onMessage { ctx ->
val user = ctx.messageAsClass<User>() // convert from json string to object
ctx.send(user) // convert to json string and send back
}
ws.onClose { ctx -> println("Closed") }
ws.onError { ctx -> println("Errored") }
}
```
### Filters and Mappers
```kotlin
config.routes.before("/some-path/*") { ctx -> ... } // runs before requests to /some-path/*
config.routes.before { ctx -> ... } // runs before all requests
config.routes.after { ctx -> ... } // runs after all requests
config.routes.exception(Exception::class.java) { e, ctx -> ... } // runs if uncaught Exception
config.routes.error(404) { ctx -> ... } // runs if status is 404 (after all other handlers)
config.routes.wsBefore("/some-path/*") { ws -> ... } // runs before ws events on /some-path/*
config.routes.wsBefore { ws -> ... } // runs before all ws events
config.routes.wsAfter { ws -> ... } // runs after all ws events
config.routes.wsException(Exception::class.java) { e, ctx -> ... } // runs if uncaught Exception in ws handler
```
### JSON-mapping
```kotlin
var todos = arrayOf(...)
config.routes.get("/todos") { ctx -> // map array of Todos to json-string
ctx.json(todos)
}
config.routes.put("/todos") { ctx -> // map request-body (json) to array of Todos
todos = ctx.bodyAsClass<Array<Todo>>()
ctx.status(204)
}
```
### File uploads
```kotlin
config.routes.post("/upload") { ctx ->
ctx.uploadedFiles("files").forEach { uploadedFile ->
FileUtil.streamToFile(uploadedFile.content(), "upload/${uploadedFile.filename()}")
}
}
```
## Plugins
Javalin has a plugin system that allows you to add functionality to the core library.
You can find a list of plugins [here](https://javalin.io/plugins).
Installing a plugin is as easy as adding a dependency to your project and registering it with Javalin:
```kotlin
Javalin.create { config ->
config.registerPlugin(MyPlugin())
}
```
Some of the most popular plugins are:
### OpenAPI Plugin
The [Javalin OpenAPI](https://github.com/javalin/javalin-openapi) plugin allows you to generate an OpenAPI 3.0 specification for your API at compile time.
Annotate your routes with `@OpenApi` to generate the specification:
```kotlin
@OpenApi(
summary = "Get all users",
operationId = "getAllUsers",
tags = ["User"],
responses = [OpenApiResponse("200", [OpenApiContent(Array<User>::class)])],
path = "/users",
methods = [HttpMethod.GET]
)
fun getAll(ctx: Context) {
ctx.json(UserService.getAll())
}
```
Swagger UI and ReDoc UI implementations for viewing the generated specification in your browser are also available.
For more information, see the [Javalin OpenAPI Wiki](https://github.com/javalin/javalin-openapi/wiki).
### SSL Plugin
The [Javalin SSL](https://javalin.io/plugins/ssl-helpers) plugin allows you to easily configure SSL for your Javalin server, supporting a variety of formats such as PEM, PKCS12, DER, P7B, and JKS.
Enabling SSL on the 443 port is as easy as:
```kotlin
val plugin = SslPlugin { conf ->
conf.pemFromPath("/path/to/cert.pem", "/path/to/key.pem")
}
Javalin.create { javalinConfig ->
javalinConfig.registerPlugin(plugin)
}.start()
```
## Sponsors
| Logo | Sponsor | Amount |
|------|---------|--------|
| <img src="https://github.com/user-attachments/assets/07bf134b-db7a-4e53-b3db-f1681b0443ff" alt="Barbary Software" width="32" height="32"> | [@barbarysoftware](https://github.com/sponsors/barbarysoftware) | (50 USD/m) |
| <img src="https://github.com/user-attachments/assets/06236654-649d-46dd-b174-11ce61e325ec" alt="Vasilis Soumakis" width="32" height="32"> | <a href="https://github.com/VassilisSoum">@VassilisSoum</a> | (25 USD/m) |
## Special thanks
* Blake Mizerany, for creating [Sinatra](http://www.sinatrarb.com/)
* Per Wendel, for creating [Spark](http://sparkjava.com/)
* [Christian Rasmussen](https://github.com/chrrasmussen), for being a great guy
* [Per Kristian Kummermo](https://github.com/pkkummermo), also for being a great guy
================================================
FILE: .github/copilot-instructions.md
================================================
# Javalin Web Framework
Javalin is a lightweight web framework for Java and Kotlin built on top of Jetty. This is a multi-module Maven project with Java 17+ support.
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
## Working Effectively
### Bootstrap and Build
- **REQUIREMENT**: Always run `./mvnw package` before `./mvnw test` to avoid OSGI dependency errors
- Build without tests: `./mvnw package -DskipTests --batch-mode` -- takes 60 seconds. NEVER CANCEL. Set timeout to 120+ seconds.
- Build with tests: `./mvnw package --batch-mode` -- takes 3+ minutes. NEVER CANCEL. Set timeout to 300+ seconds.
- **CRITICAL**: Browser tests fail in CI environment due to missing WebDriver - this is expected and normal
- Clean build: `./mvnw clean package -DskipTests --batch-mode` -- takes 90 seconds. NEVER CANCEL. Set timeout to 180+ seconds.
- Full CI build: `./mvnw -DRunningOnCi=true clean verify --batch-mode` -- takes 4+ minutes. NEVER CANCEL. Set timeout to 360+ seconds.
### Testing
- Run all tests: `./mvnw test --batch-mode` -- takes 2+ minutes. NEVER CANCEL. Set timeout to 240+ seconds.
- Run specific module tests: `./mvnw test -pl javalin --batch-mode`
- **EXPECTED FAILURES**: ~20 browser tests fail in CI environment (TestJavalinVueBrowser) due to WebDriver unavailability
- Non-browser tests pass reliably and provide good validation coverage
### Project Structure
- **Root**: Multi-module Maven project with 11 modules
- **Main module**: `javalin/` - Core framework implementation
- **Key modules**:
- `javalin-testtools/` - Testing utilities
- `javalin-rendering/` - Template engine plugins
- `javalin-ssl/` - SSL/TLS helpers
- `javalin-bundle/` - All-in-one bundle
## Validation Scenarios
### Always validate changes with these scenarios:
#### 1. Basic Server Functionality
```java
// Test script: Validate core Javalin functionality
var app = Javalin.create(config -> {
// Basic config test
config.routes.get("/", ctx -> ctx.result("Hello Javalin!"));
config.routes.get("/health", ctx -> ctx.json(Map.of("status", "ok")));
}).start(7070);
// Test HTTP requests work
// Verify responses are correct
// Stop gracefully: app.stop()
```
#### 2. Build Validation Steps
1. `./mvnw clean` - Clean all build artifacts
2. `./mvnw package -DskipTests --batch-mode` - Verify compilation (60s)
3. Test basic server functionality with above scenario
4. `./mvnw test -pl javalin --batch-mode` - Run core tests (120s)
#### 3. Module Dependencies
- Always test the main `javalin` module can be used standalone
- Verify proper module separation (no circular dependencies)
- Check that examples in README.md work correctly
## Common Tasks
### Repository Navigation
```
javalin/
├── javalin/ # Core framework (main module)
│ ├── src/main/java/io/javalin/
│ │ ├── Javalin.java # Main entry point
│ │ ├── http/ # HTTP handling
│ │ ├── router/ # Routing implementation
│ │ ├── config/ # Configuration
│ │ └── websocket/ # WebSocket support
│ └── src/test/java/ # Core tests
├── javalin-testtools/ # Testing utilities
├── javalin-rendering/ # Template engines
├── javalin-ssl/ # SSL helpers
└── .github/workflows/ # CI configuration
```
### Development Commands
- **Java version**: JDK 17+ required (project targets Java 17)
- **Maven wrapper**: `./mvnw` (no system Maven installation required)
- **Editor config**: `.editorconfig` - 4 spaces, UTF-8, LF line endings
- **Code style**: IntelliJ defaults with import optimization
### Commit Message Convention
Follow the repository's strict commit message format:
```
[component/area]: Description of change
```
**Examples:**
- `[core] Add feature for HTTP request handling`
- `[workflow] Update GitHub Actions dependencies`
- `[deps] Bump Jackson version to fix security issue`
- `[static-files] Fix path decoding for special characters`
- `[context] Add method to disable response compression`
- `[tests] Add unit tests for new validation logic`
- `[github] Update documentation and README files`
**Component categories commonly used:**
- `[core]` - Core framework functionality
- `[context]` - Request/response context changes
- `[router]` - Routing and handler logic
- `[static-files]` - Static file serving
- `[websocket]` - WebSocket functionality
- `[jetty]` - Jetty server configuration
- `[deps]` - Dependency updates
- `[tests]` - Test-related changes
- `[workflow]` - GitHub Actions and CI
- `[github]` - Documentation and repository files
- `[maven-release-plugin]` - Release process
- `[ssl]` - SSL/TLS functionality
### Testing Guidelines
- **Unit tests**: Fast, no external dependencies
- **Integration tests**: Use TestUtil.test() helper for server lifecycle
- **Browser tests**: Use WebDriverUtil (fails in CI, works locally with Chrome)
- **Test utilities**: io.javalin.testing package provides helpers
### Key Files to Monitor
- `pom.xml` - Main project configuration and dependencies
- `javalin/pom.xml` - Core module configuration
- `javalin/src/main/java/io/javalin/Javalin.java` - Main API entry point
- `.github/workflows/main.yml` - CI configuration and build validation
- `README.md` - Developer instructions (different from public README)
- `.github/README.md` - Public documentation and examples
### Timing Expectations
- **Clean build**: 60-90 seconds
- **Full test suite**: 2-4 minutes
- **Single module tests**: 30-120 seconds
- **Application startup**: 1-2 seconds
- **NEVER CANCEL** long-running builds - they will complete successfully
### Known Issues and Workarounds
- **OSGI Error**: Always run `package` before `test`
- **Browser Test Failures**: Expected in CI - missing WebDriver dependencies
- **Profile Warning**: CI uses `-P dev` but profile doesn't exist (safely ignored)
- **Multiple SLF4J Bindings**: Warning is normal (both logback and slf4j-simple present)
## Quick Start Validation
After making changes, always run this validation sequence:
1. **Clean build**: `./mvnw clean package -DskipTests --batch-mode`
2. **Test core functionality**: Create and test basic Javalin server as shown above
3. **Run tests**: `./mvnw test -pl javalin --batch-mode`
4. **Verify specific changes**: Test your specific functionality thoroughly
This ensures your changes integrate properly with the framework and don't break core functionality.
## Javalin Philosophy and Design Patterns
Javalin is designed as a lightweight library (not a framework) with these core principles:
### Core Principles
- **No Annotations**: All configuration is done through code, not annotations
- **No Reflection**: Everything is explicit and statically typed
- **No Magic**: Just plain code that's easy to understand and debug
- **No Extension Required**: You don't need to extend any base classes
- **Functional First**: Heavy use of lambdas and functional interfaces
- **Consumer-based Configuration**: All configuration uses `Consumer<Config>` pattern
### Configuration Patterns
#### Always Use Consumers for Configuration
Javalin uses the consumer pattern extensively for configuration. This allows for flexible, type-safe configuration:
```java
// CORRECT: Using consumer pattern
var app = Javalin.create(config -> {
config.http.asyncTimeout = 10_000L;
config.staticFiles.add("/public");
config.useVirtualThreads = true;
});
// AVOID: Don't try to configure after creation
var app = Javalin.create();
app.unsafe.http.asyncTimeout = 10_000L; // Avoid using 'unsafe' unless necessary
```
#### Nested Configuration
Configuration objects are organized hierarchically and use consumers:
```java
Javalin.create(config -> {
// HTTP layer configuration
config.http.asyncTimeout = 10_000L;
config.http.maxRequestSize = 1_000_000L;
// Router configuration
config.router.contextPath = "/api";
config.router.treatMultipleSlashesAsSingleSlash = true;
// Static files
config.staticFiles.add("/public");
config.staticFiles.enableWebjars();
// Events using consumer
config.events(events -> {
events.serverStarting(() -> System.out.println("Starting..."));
events.serverStarted(() -> System.out.println("Started!"));
});
});
```
### Handler Patterns
#### Functional Interface Handlers
All handlers are functional interfaces - use lambdas or method references.
**NOTE**: In Javalin 7, routes are defined inside `Javalin.create()` using `config.routes`:
```java
// Lambda handler - PREFERRED for simple cases
Javalin.create(config -> {
config.routes.get("/hello", ctx -> ctx.result("Hello"));
// Multi-line lambda
config.routes.post("/users", ctx -> {
User user = ctx.bodyAsClass(User.class);
UserService.create(user);
ctx.status(201).json(user);
});
// Method reference - PREFERRED for complex logic
config.routes.get("/users", UserController::getAll);
config.routes.post("/users", UserController::create);
});
// AVOID: Don't create anonymous classes
config.routes.get("/bad", new Handler() {
@Override
public void handle(Context ctx) { // Too verbose
ctx.result("Bad");
}
});
```
#### Handler Return Type
Handlers have void return type - always use `ctx.result()` or `ctx.json()` to return data:
```java
// CORRECT: Use ctx methods to set response
Javalin.create(config -> {
config.routes.get("/data", ctx -> {
ctx.json(Map.of("key", "value"));
});
});
// AVOID: Don't return values
config.routes.get("/wrong", ctx -> {
return "Hello"; // WRONG - this doesn't work
});
```
### Routing Patterns
#### Two Routing Styles
Javalin supports two routing styles - choose based on your needs:
```java
// Style 1: Direct routing within config.routes - simple and clear
Javalin.create(config -> {
config.routes.get("/users", UserController::getAll);
config.routes.post("/users", UserController::create);
config.routes.get("/users/{id}", UserController::getOne);
config.routes.delete("/users/{id}", UserController::delete);
});
// Style 2: ApiBuilder - better for nested structures
import io.javalin.apibuilder.ApiBuilder.*;
Javalin.create(config -> {
config.routes.apiBuilder(() -> {
path("/users", () -> {
get(UserController::getAll);
post(UserController::create);
path("/{id}", () -> {
get(UserController::getOne);
patch(UserController::update);
delete(UserController::delete);
});
ws("/events", UserController::webSocketEvents);
});
});
});
```
#### Path Parameters and Query Parameters
```java
// Path parameters with {paramName}
Javalin.create(config -> {
config.routes.get("/users/{userId}/posts/{postId}", ctx -> {
String userId = ctx.pathParam("userId");
String postId = ctx.pathParam("postId");
ctx.json(PostService.getPost(userId, postId));
});
// Query parameters
config.routes.get("/search", ctx -> {
String query = ctx.queryParam("q"); // nullable
int page = ctx.queryParamAsClass("page", Integer.class).getOrDefault(1);
ctx.json(SearchService.search(query, page));
});
});
```
### Lifecycle Management
#### Before and After Handlers
Use lifecycle handlers for cross-cutting concerns:
```java
Javalin.create(config -> {
// Before all requests
config.routes.before(ctx -> {
ctx.header("X-Request-Id", UUID.randomUUID().toString());
});
// Before specific paths
config.routes.before("/api/*", ctx -> {
// Auth check, logging, etc.
if (!isAuthenticated(ctx)) {
throw new UnauthorizedResponse();
}
});
// beforeMatched runs after routing is resolved
config.routes.beforeMatched(ctx -> {
// Access route-specific data like roles
if (!hasRequiredRole(ctx)) {
throw new ForbiddenResponse();
}
});
// After handlers
config.routes.after(ctx -> {
// Logging, cleanup, etc.
log.info("Request completed: {}", ctx.status());
});
});
```
#### Exception Handling
Use exception handlers instead of try-catch in every route:
```java
Javalin.create(config -> {
// Specific exception handling
config.routes.exception(ValidationException.class, (e, ctx) -> {
ctx.status(400).json(Map.of("error", e.getMessage()));
});
config.routes.exception(NotFoundException.class, (e, ctx) -> {
ctx.status(404).json(Map.of("error", "Not found"));
});
// Generic exception handling
config.routes.exception(Exception.class, (e, ctx) -> {
log.error("Unhandled exception", e);
ctx.status(500).json(Map.of("error", "Internal server error"));
});
});
// In handlers, just throw - don't catch
app.get("/users/{id}", ctx -> {
User user = UserService.findById(ctx.pathParam("id"))
.orElseThrow(() -> new NotFoundException("User not found"));
ctx.json(user);
});
```
#### Error Handlers
Error handlers run when a specific HTTP status is set:
```java
Javalin.create(config -> {
config.routes.error(404, ctx -> {
ctx.json(Map.of("error", "Page not found"));
});
config.routes.error(500, ctx -> {
ctx.json(Map.of("error", "Server error"));
});
});
```
### Context Usage Patterns
#### Request Data Access
The Context object provides all request information:
```java
Javalin.create(config -> {
config.routes.post("/submit", ctx -> {
// Body parsing
User user = ctx.bodyAsClass(User.class);
String rawBody = ctx.body();
// Form parameters
String name = ctx.formParam("name");
// Uploaded files
ctx.uploadedFiles("files").forEach(file -> {
saveFile(file.content(), file.filename());
});
// Headers
String authHeader = ctx.header("Authorization");
Map<String, String> headers = ctx.headerMap();
// Cookies
String session = ctx.cookie("session");
// Request info
String method = ctx.method().toString();
String path = ctx.path();
String ip = ctx.ip();
});
});
```
#### Response Building
Build responses using Context methods:
```java
Javalin.create(config -> {
config.routes.get("/response", ctx -> {
// JSON response (most common)
ctx.json(myObject);
// Plain text
ctx.result("Hello World");
// HTML
ctx.html("<h1>Hello</h1>");
// Status codes
ctx.status(201);
ctx.status(HttpStatus.CREATED);
// Headers
ctx.header("X-Custom", "value");
ctx.contentType("application/json");
// Cookies
ctx.cookie("session", "abc123");
ctx.cookie(new Cookie("name", "value", "/path", 3600));
// Redirects
ctx.redirect("/new-location");
ctx.redirect("/new-location", HttpStatus.PERMANENT_REDIRECT);
});
});
```
### Plugin Patterns
#### Using Plugins
Plugins are registered during configuration:
```java
import io.javalin.plugin.bundled.*;
Javalin.create(config -> {
// Simple plugins without config
config.registerPlugin(new DevLoggingPlugin());
// Plugins with configuration using consumer pattern
config.registerPlugin(new CorsPlugin(cors -> {
cors.addRule(rule -> {
rule.anyHost();
});
}));
// SSL Plugin
config.registerPlugin(new SSLPlugin(ssl -> {
ssl.pemFromPath("/path/to/cert.pem", "/path/to/key.pem");
}));
});
```
#### Creating Custom Plugins
Plugins extend the Plugin base class and use consumers for configuration:
```java
// Plugin with configuration
class MyPlugin extends Plugin<MyPlugin.Config> {
MyPlugin(Consumer<Config> userConfig) {
super(userConfig, new Config());
}
@Override
public void onStart(JavalinConfig config) {
// Register handlers, configure Javalin, etc.
config.routes.before(ctx -> {
// Plugin logic using pluginConfig
if (pluginConfig.enabled) {
doSomething();
}
});
}
public static class Config {
public boolean enabled = true;
public int timeout = 5000;
}
}
// Usage
Javalin.create(config -> {
config.registerPlugin(new MyPlugin(cfg -> {
cfg.enabled = true;
cfg.timeout = 10000;
}));
});
```
#### Context-extending Plugins
Use ContextPlugin to add extension methods to Context:
```java
class RateLimitPlugin extends ContextPlugin<RateLimitPlugin.Config, RateLimitPlugin.Extension> {
RateLimitPlugin(Consumer<Config> userConfig) {
super(userConfig, new Config());
}
@Override
public Extension createExtension(Context context) {
return new Extension(context);
}
class Extension {
Context ctx;
Extension(Context ctx) { this.ctx = ctx; }
public void checkLimit() {
// Rate limiting logic
}
}
static class Config {
int limit = 100;
}
}
// Usage in handlers
Javalin.create(config -> {
config.routes.get("/", ctx -> {
ctx.with(RateLimitPlugin.class).checkLimit();
ctx.result("OK");
});
});
```
### WebSocket Patterns
#### WebSocket Handlers
WebSocket handlers use a consumer pattern for configuration:
```java
Javalin.create(config -> {
config.routes.ws("/chat", ws -> {
ws.onConnect(ctx -> {
System.out.println("Connected: " + ctx.sessionId());
ctx.send("Welcome!");
});
ws.onMessage(ctx -> {
String message = ctx.message();
// Broadcast to all connected clients
ctx.sessionManager().sessions().forEach(session -> {
session.send(message);
});
});
ws.onClose(ctx -> {
System.out.println("Closed: " + ctx.sessionId());
});
ws.onError(ctx -> {
System.err.println("Error: " + ctx.error());
});
});
});
// With ApiBuilder
import io.javalin.apibuilder.ApiBuilder.*;
Javalin.create(config -> {
config.routes.apiBuilder(() -> {
ws("/websocket", ws -> {
ws.onConnect(ctx -> ctx.send("Hello"));
ws.onMessage(ctx -> ctx.send("Echo: " + ctx.message()));
});
});
});
```
#### JSON over WebSocket
```java
Javalin.create(config -> {
config.routes.ws("/events", ws -> {
ws.onMessage(ctx -> {
// Parse JSON message
Event event = ctx.messageAsClass(Event.class);
// Send JSON response
ctx.send(new EventResponse(event.getId(), "processed"));
});
});
});
```
### Async and Future Patterns
#### CompletableFuture Support
Javalin has built-in support for async operations:
```java
Javalin.create(config -> {
config.routes.get("/async", ctx -> {
ctx.future(() -> {
return CompletableFuture.supplyAsync(() -> {
// Long-running operation
return expensiveOperation();
}).thenApply(result -> {
ctx.json(result);
return null;
});
});
});
// With executor
ExecutorService executor = Executors.newFixedThreadPool(10);
config.routes.get("/async-executor", ctx -> {
ctx.future(() -> {
return CompletableFuture.supplyAsync(() -> {
return database.query();
}, executor).thenApply(data -> {
ctx.json(data);
return null;
});
});
});
});
```
#### Virtual Threads (Java 21+)
Enable virtual threads for better async performance:
```java
Javalin.create(config -> {
config.useVirtualThreads = true;
}).start(7070);
```
### JSON Serialization Patterns
#### Using Built-in JSON Support
Javalin uses Jackson by default:
```java
Javalin.create(config -> {
// Serialize to JSON
config.routes.get("/users", ctx -> {
List<User> users = UserService.getAll();
ctx.json(users); // Automatic serialization
});
// Deserialize from JSON
config.routes.post("/users", ctx -> {
User user = ctx.bodyAsClass(User.class);
UserService.save(user);
ctx.status(201).json(user);
});
// Type-safe deserialization with generics
config.routes.post("/items", ctx -> {
List<Item> items = ctx.bodyAsClass(new TypeReference<List<Item>>() {});
ctx.json(items);
});
});
```
#### Custom JSON Mapper
Configure a custom JSON mapper if needed:
```java
Javalin.create(config -> {
config.jsonMapper(new JavalinJackson()); // or custom implementation
});
```
### Common Anti-Patterns to Avoid
#### ❌ Don't Use Annotations
```java
// WRONG - Javalin doesn't use annotations
@Path("/users")
@GET
public void getUsers() { } // This won't work
```
#### ❌ Don't Extend Classes
```java
// WRONG - No need to extend anything
public class MyApp extends Javalin { } // Don't do this
```
#### ❌ Don't Use Reflection
```java
// WRONG - Javalin is reflection-free
config.routes.get("/users", "UserController.getAll"); // String-based routing doesn't exist
```
#### ❌ Don't Configure After Creation (Usually)
```java
// AVOID - Configure during creation
var app = Javalin.create();
app.unsafe.http.asyncTimeout = 5000; // Avoid 'unsafe' access
// PREFERRED - Configure in create()
var app = Javalin.create(config -> {
config.http.asyncTimeout = 5000;
});
```
#### ❌ Don't Use Old-style Direct Routing (Pre-v7)
```java
// WRONG - This was the old Javalin 6 API
var app = Javalin.create();
app.get("/hello", ctx -> ctx.result("Hello")); // Doesn't exist in v7+
// CORRECT - v7+ routes go in config
Javalin.create(config -> {
config.routes.get("/hello", ctx -> ctx.result("Hello"));
});
```
#### ❌ Don't Block WebSocket Handlers
```java
// WRONG - Blocking in WebSocket handler
ws.onMessage(ctx -> {
Thread.sleep(5000); // Don't block!
ctx.send("Delayed");
});
// CORRECT - Use async if needed
ws.onMessage(ctx -> {
CompletableFuture.runAsync(() -> {
// Long operation
}).thenRun(() -> ctx.send("Done"));
});
```
#### ❌ Don't Catch Everything
```java
// AVOID - Use exception handlers instead
Javalin.create(config -> {
config.routes.get("/users", ctx -> {
try {
User user = UserService.find(id);
ctx.json(user);
} catch (Exception e) {
ctx.status(500).result("Error");
}
});
});
// PREFERRED - Let exception handlers handle it
Javalin.create(config -> {
config.routes.exception(NotFoundException.class, (e, ctx) -> {
ctx.status(404).json(Map.of("error", e.getMessage()));
});
config.routes.get("/users", ctx -> {
User user = UserService.find(id); // Just throw if not found
ctx.json(user);
});
});
```
### Testing Patterns
#### Use TestUtil for Integration Tests
The TestUtil helper manages server lifecycle:
```java
@Test
void testEndpoint() {
TestUtil.test((app, http) -> {
// Define routes in the configuration
Javalin configured = Javalin.create(config -> {
config.routes.get("/hello", ctx -> ctx.result("Hello"));
});
// Note: TestUtil.test() expects routes to be added via app parameter
// For simple tests, use the app parameter directly:
});
// Or use it this way:
TestUtil.test(Javalin.create(config -> {
config.routes.get("/hello", ctx -> ctx.result("Hello"));
}), (app, http) -> {
HttpResponse<String> response = http.get("/hello");
assertThat(response.body()).isEqualTo("Hello");
assertThat(response.statusCode()).isEqualTo(200);
});
}
// With custom Javalin config
@Test
void testWithConfig() {
Javalin app = Javalin.create(config -> {
config.http.asyncTimeout = 5000L;
config.routes.get("/test", ctx -> ctx.result("Test"));
});
TestUtil.test(app, (javalin, http) -> {
assertThat(http.get("/test").statusCode()).isEqualTo(200);
});
}
```
#### Unit Testing Handlers
Test handlers independently using mocks:
```java
@Test
void testHandler() throws Exception {
Context ctx = mock(Context.class);
when(ctx.pathParam("id")).thenReturn("123");
UserController.getUser(ctx);
verify(ctx).json(any(User.class));
}
```
### Best Practices Summary
1. **Always use consumers for configuration** - This is the Javalin way
2. **Prefer lambdas and method references** - Keep handlers clean and functional
3. **Use exception handlers** - Don't catch exceptions in every handler
4. **Choose the right routing style** - Direct for simple APIs, ApiBuilder for complex structures
5. **Leverage lifecycle handlers** - Use before/after for cross-cutting concerns
6. **Keep handlers focused** - Extract business logic to service classes
7. **Use plugins for reusable features** - Don't repeat yourself across apps
8. **Test with TestUtil** - It handles server lifecycle properly
9. **Embrace the functional style** - Javalin is designed for it
10. **Read the docs** - https://javalin.io/documentation has comprehensive examples
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "monthly"
time: "04:30" # this is in UTC time
open-pull-requests-limit: 10
commit-message:
prefix: "[deps]"
labels:
- "dependencies"
target-branch: "master"
groups:
dependencies:
patterns:
- "*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
commit-message:
prefix: "[workflow]"
labels:
- "dependencies"
target-branch: "master"
groups:
dependencies:
patterns:
- "*"
================================================
FILE: .github/workflows/cleanup-performance-preview.yml
================================================
name: Cleanup Performance Preview
on:
pull_request:
types:
- closed
permissions:
contents: read
jobs:
dispatch-cleanup:
runs-on: ubuntu-latest
steps:
- name: Dispatch preview cleanup workflow
if: ${{ secrets.PERF_ACTIONS_CONTENTS_RW != '' }}
uses: actions/github-script@v8
with:
github-token: ${{ secrets.PERF_ACTIONS_CONTENTS_RW }}
script: |
await github.request("POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches", {
owner: "javalin",
repo: "javalin-performance-tests-testing",
workflow_id: "cleanup-pr-preview.yml",
ref: "main",
inputs: {
prNumber: `${{ github.event.pull_request.number }}`
}
});
- name: Skip when cleanup token is not configured
if: ${{ secrets.PERF_ACTIONS_CONTENTS_RW == '' }}
run: echo "Skipping cleanup dispatch because PERF_ACTIONS_CONTENTS_RW is not configured."
================================================
FILE: .github/workflows/main.yml
================================================
name: Test all JDKs on all OSes
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
java_version: [17, 21]
os: [windows-latest, macos-14, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up JDK ${{ matrix.java_version }}
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: ${{ matrix.java_version }}
- name: Cache local Maven repository
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Make Maven Wrapper executable
if: contains(matrix.os, 'win') == false
run: chmod +x ./mvnw
- name: Build with Maven
run: ./mvnw -DRunningOnCi=true package --file pom.xml --batch-mode
env:
MAVEN_OPTS: -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
coverage:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: 21
- name: Cache local Maven repository
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Make Maven Wrapper executable
run: chmod +x ./mvnw
- name: Build with Maven
run: ./mvnw -P dev -DRunningOnCi=true clean verify --file pom.xml --batch-mode
env:
MAVEN_OPTS: -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5.5.2
with:
files: "${{ github.workspace }}/javalin-utils/coverage/target/site/jacoco-aggregate/jacoco.xml"
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} #Must be added for dependabot too
================================================
FILE: .github/workflows/publish-snapshots.yml
================================================
name: Snapshot build
on:
push:
branches: [ 'master' ]
jobs:
publish:
if: |
github.repository == 'javalin/javalin' &&
!contains(github.event.head_commit.message, '[maven-release-plugin] prepare release')
name: Publish snapshot
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up JDK17
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: 17
- name: Grant execute permission for mvnw
run: chmod +x ./mvnw
- uses: s4u/maven-settings-action@v4.0.0
with:
servers: |
[{
"id": "reposilite-repository",
"username": "${{ secrets.MAVEN_NAME }}",
"password": "${{ secrets.MAVEN_SECRET }}"
}]
- name: Publish with Maven
run: ./mvnw -DRunningOnCi=true clean deploy --file pom.xml --batch-mode -P publish-snapshot
================================================
FILE: .github/workflows/test-performance-command.yml
================================================
name: Test performance command
on:
issue_comment:
types:
- created
permissions:
contents: read
pull-requests: read
issues: write
jobs:
evaluate:
if: github.event.issue.pull_request != null
runs-on: ubuntu-latest
outputs:
is_command: ${{ steps.evaluate.outputs.is_command }}
is_authorized: ${{ steps.evaluate.outputs.is_authorized }}
reason: ${{ steps.evaluate.outputs.reason }}
pr_number: ${{ steps.evaluate.outputs.pr_number }}
pr_url: ${{ steps.evaluate.outputs.pr_url }}
source_repository: ${{ steps.evaluate.outputs.source_repository }}
source_sha: ${{ steps.evaluate.outputs.source_sha }}
source_ref: ${{ steps.evaluate.outputs.source_ref }}
source_tarball_url: ${{ steps.evaluate.outputs.source_tarball_url }}
steps:
- name: Evaluate command
id: evaluate
uses: actions/github-script@v8
with:
script: |
const commentBody = (context.payload.comment?.body || "").replace(/\s+/g, " ").trim();
const lowered = commentBody.toLowerCase();
const isCommand = lowered === "/test performance" || lowered.startsWith("/test performance ");
core.setOutput("is_command", isCommand ? "true" : "false");
if (!isCommand) {
core.setOutput("is_authorized", "false");
core.setOutput("reason", "Not a /test performance command.");
return;
}
const association = context.payload.comment?.author_association || "NONE";
const allowedAssociations = new Set(["OWNER", "MEMBER"]);
const isAuthorized = allowedAssociations.has(association);
core.setOutput("is_authorized", isAuthorized ? "true" : "false");
if (!isAuthorized) {
core.setOutput("reason", "Only maintainers can use /test performance.");
return;
}
const prNumber = context.issue.number;
const { owner, repo } = context.repo;
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: prNumber,
});
if (pr.state !== "open") {
core.setOutput("is_authorized", "false");
core.setOutput("reason", "PR is not open.");
return;
}
if (!pr.head?.repo?.full_name || !pr.head?.sha || !pr.head?.ref) {
core.setOutput("is_authorized", "false");
core.setOutput("reason", "Could not resolve PR head snapshot details.");
return;
}
const sourceRepository = pr.head.repo.full_name;
const sourceSha = pr.head.sha;
const sourceRef = pr.head.ref;
core.setOutput("reason", `Command accepted for ${sourceRepository}@${sourceSha}.`);
core.setOutput("pr_number", String(pr.number));
core.setOutput("pr_url", pr.html_url);
core.setOutput("source_repository", sourceRepository);
core.setOutput("source_sha", sourceSha);
core.setOutput("source_ref", sourceRef);
core.setOutput("source_tarball_url", `https://api.github.com/repos/${sourceRepository}/tarball/${sourceSha}`);
reject:
needs: evaluate
if: needs.evaluate.outputs.is_command == 'true' && needs.evaluate.outputs.is_authorized != 'true'
runs-on: ubuntu-latest
steps:
- name: Explain rejection
uses: actions/github-script@v8
with:
script: |
const reason = ${{ toJSON(needs.evaluate.outputs.reason) }};
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Ignored \`/test performance\`: ${reason}`,
});
dispatch:
needs: evaluate
if: needs.evaluate.outputs.is_command == 'true' && needs.evaluate.outputs.is_authorized == 'true'
runs-on: ubuntu-latest
steps:
- name: Dispatch benchmark workflow
id: dispatch
continue-on-error: true
uses: actions/github-script@v8
with:
github-token: ${{ secrets.PERF_ACTIONS_CONTENTS_RW }}
script: |
await github.request("POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches", {
owner: "javalin",
repo: "javalin-performance-tests-testing",
workflow_id: "benchmark-pr.yml",
ref: "main",
inputs: {
sourceRepository: `${{ needs.evaluate.outputs.source_repository }}`,
sourceSha: `${{ needs.evaluate.outputs.source_sha }}`,
sourceRef: `${{ needs.evaluate.outputs.source_ref }}`,
sourcePrNumber: `${{ needs.evaluate.outputs.pr_number }}`,
triggerRepository: `${{ github.repository }}`,
triggerPrNumber: `${{ needs.evaluate.outputs.pr_number }}`,
triggerPrUrl: `${{ needs.evaluate.outputs.pr_url }}`
}
});
- name: Comment success
if: steps.dispatch.outcome == 'success'
continue-on-error: true
uses: actions/github-script@v8
with:
github-token: ${{ secrets.JAVALIN_PR_RW }}
script: |
const workflowUrl = "https://github.com/javalin/javalin-performance-tests-testing/actions/workflows/benchmark-pr.yml";
const previewUrl = "https://javalin.github.io/javalin-performance-tests-testing/pr-previews/pr-${{ needs.evaluate.outputs.pr_number }}/latest/";
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body:
"Triggered performance benchmark pipeline.\n\n" +
`- Snapshot: \`${{ needs.evaluate.outputs.source_repository }}:${{ needs.evaluate.outputs.source_ref }}\` (\`${{ needs.evaluate.outputs.source_sha }}\`)\n` +
`- Preview (latest): ${previewUrl}\n` +
`- Workflow: ${workflowUrl}`,
});
- name: Comment failure
if: steps.dispatch.outcome != 'success'
continue-on-error: true
uses: actions/github-script@v8
with:
github-token: ${{ secrets.JAVALIN_PR_RW }}
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body:
"Failed to trigger performance benchmark pipeline.\n\n" +
"Check whether the `PERF_ACTIONS_CONTENTS_RW` secret is configured with access to `javalin/javalin-performance-tests-testing` workflows.",
});
- name: Fail job if dispatch failed
if: steps.dispatch.outcome != 'success'
run: exit 1
================================================
FILE: .gitignore
================================================
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.idea
*.iml
# ignore Eclipse specifics
.classpath
.settings
.project
.factorypath
# ignore temporary test files
javalin/src/test/external/test*.txt
# ignore JTE generated classes
jte-classes/
# ignore flatten-maven-plugin output
.flattened-pom.xml
================================================
FILE: .mvn/wrapper/maven-wrapper.properties
================================================
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 David Åse
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Javalin
This readme is for Javalin developers.
If you are looking for the general readme, see [.github/README.md](.github/README.md).
## Getting started
```sh
gh repo clone javalin/javalin
cd javalin
./mvnw package #(or `mvn package` if you have maven installed)
./mvnw test #(or `mvn test` if you have maven installed)
```
If you run `test` before `package`, you will get an error in the OSGI artifact:
```
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-dependency-plugin:2.8:unpack-dependencies (unpack-everything) on project javalin-osgi: Artifact has not been packaged yet. When used on reactor artifact, unpack should be executed after packaging: see MDEP-98. -> [Help 1]
```
## Running maven commands
We have Maven wrapper included in the project, which means that
you can run Maven commands without having Maven installed on your system.
Simply replace any `mvn goal` command with `./mvnw goal`.
## Deploy
The `sonatype-oss-release` profile is used for releasing the project artifacts to Sonatype OSSRH (OSS Repository Hosting).
This is only used by tipsy to release the project.
================================================
FILE: jacoco-coverage-report/README.md
================================================
# Jacoco Coverage Report
This module is used for Jacoco code coverage report aggregation.
## Jacoco Report Path
The Jacoco report can be found at the following path, relative to the root of the project:
`jacoco-coverage-report/target/site/jacoco-aggregate/jacoco.xml`
## Generating the Jacoco Report
To generate the Jacoco report, run the following command from the root of the project:
`mvn clean verify`
## Viewing the Jacoco Report
The Jacoco report can be viewed by opening the following file in a web browser:
`jacoco-coverage-report/target/site/jacoco-aggregate/index.html`
Or by using Codecov to view the report online here: [](https://codecov.io/gh/javalin/javalin)
## Coverage graphs
### Sunburst
[](https://codecov.io/gh/javalin/javalin)
### Icicle
[](https://codecov.io/gh/javalin/javalin)
### Treemap / Grid
[](https://codecov.io/gh/javalin/javalin)
================================================
FILE: jacoco-coverage-report/pom.xml
================================================
<?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>
<parent>
<groupId>io.javalin</groupId>
<artifactId>javalin-parent</artifactId>
<version>7.1.1-SNAPSHOT</version>
</parent>
<artifactId>jacoco-coverage-report</artifactId>
<packaging>pom</packaging>
<name>JaCoCo Coverage Report</name>
<description>Aggregated code coverage report for all Javalin modules</description>
<dependencies>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-testtools</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-context-mock</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-velocity</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-freemarker</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-thymeleaf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-mustache</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-pebble</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-commonmark</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.javalin.community.ssl</groupId>
<artifactId>javalin-ssl</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${deploy.plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<configuration>
<skipPublishing>true</skipPublishing>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
<configuration>
<dataFileIncludes>
<dataFileInclude>**/jacoco.exec</dataFileInclude>
</dataFileIncludes>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: javalin/module-info.java
================================================
module io.javalin {
exports io.javalin;
exports io.javalin.apibuilder;
exports io.javalin.compression;
exports io.javalin.config;
exports io.javalin.event;
exports io.javalin.http;
exports io.javalin.http.servlet;
exports io.javalin.http.sse;
exports io.javalin.http.staticfiles;
exports io.javalin.http.util;
exports io.javalin.jetty;
exports io.javalin.json;
exports io.javalin.plugin;
exports io.javalin.plugin.bundled;
exports io.javalin.rendering;
exports io.javalin.router;
exports io.javalin.security;
exports io.javalin.util;
exports io.javalin.util.function;
exports io.javalin.validation;
exports io.javalin.vue;
exports io.javalin.websocket;
requires transitive kotlin.stdlib;
requires transitive org.slf4j;
requires transitive org.eclipse.jetty.server;
requires transitive org.eclipse.jetty.ee10.servlet;
requires transitive org.eclipse.jetty.util;
requires transitive org.eclipse.jetty.websocket.core.common;
requires transitive org.eclipse.jetty.ee10.websocket.jetty.server;
requires transitive org.eclipse.jetty.websocket.api;
//optional dependencies
requires static org.jetbrains.annotations;
requires static com.aayushatharva.brotli4j;
requires static com.aayushatharva.brotli4j.service;
requires static com.github.luben.zstdjni;
requires static com.fasterxml.jackson.databind;
requires static com.fasterxml.jackson.kotlin;
requires static com.google.gson;
//Required to use the Service Loader on this type
uses org.slf4j.spi.SLF4JServiceProvider;
}
================================================
FILE: javalin/pom.xml
================================================
<?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">
<parent>
<artifactId>javalin-parent</artifactId>
<groupId>io.javalin</groupId>
<version>7.1.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>javalin</artifactId>
<name>Javalin</name>
<description>Javalin: Simple REST APIs for Java and Kotlin</description>
<dependencies>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<optional>true</optional>
</dependency>
<!-- Jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
<artifactId>jetty-ee10-websocket-jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<!-- BEGIN Optional dependencies -->
<dependency>
<groupId>com.aayushatharva.brotli4j</groupId>
<artifactId>brotli4j</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.luben</groupId>
<artifactId>zstd-jni</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<optional>true</optional>
</dependency>
<!-- END Optional dependencies -->
<!-- BEGIN Test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.mockk</groupId>
<artifactId>mockk-jvm</artifactId>
<version>${mockk.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>${unirest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>${java.websocket.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-jvm</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi</artifactId>
<version>${moshi.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi-kotlin</artifactId>
<version>${moshi.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-unixdomain-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>jetty-websocket-jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-client-transport</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>${selenium.chrome.driver.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>${webdrivermanager.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>${swagger.ui.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>**/testing/*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<executions>
<execution>
<id>add-module-infos</id>
<phase>package</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<overwriteExistingFiles>true</overwriteExistingFiles>
<module>
<moduleInfoFile>./module-info.java
</moduleInfoFile>
</module>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/performance/**</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec.plugin.version}</version>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: javalin/src/main/java/io/javalin/Javalin.java
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*
*/
package io.javalin;
import io.javalin.config.JavalinConfig;
import io.javalin.config.JavalinState;
import io.javalin.jetty.JettyServer;
import jakarta.servlet.Servlet;
import kotlin.Lazy;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import static io.javalin.util.Util.createLazy;
public class Javalin {
private final JavalinState state;
protected final Lazy<JettyServer> jettyServer;
protected Javalin(JavalinState state) {
this.state = state;
this.jettyServer = createLazy(() -> new JettyServer(this.state));
unsafe = this.state;
}
/**
* Advanced/unsafe API providing access to internal Javalin configuration.
* This exposes powerful but potentially dangerous APIs. Use with caution.
*/
@NotNull
public JavalinState unsafe;
public JettyServer jettyServer() {
return jettyServer.getValue();
}
/**
* Creates a new instance without any custom configuration.
* The server does not run until {@link Javalin#start()} is called.
*
* @return application instance
* @see Javalin#create(Consumer)
*/
public static Javalin create() {
return create(config -> {
});
}
/**
* Creates a new instance with the user provided configuration.
* The server does not run until {@link Javalin#start()} is called.
*
* @param config configuration consumer accepting {@link JavalinConfig}
* @return application instance
* @see Javalin#start()
* @see Javalin#start(int)
*/
public static Javalin create(Consumer<JavalinConfig> config) {
JavalinState state = new JavalinState();
JavalinState.applyUserConfig(state, config); // mutates app.config and app (adds http-handlers)
Javalin app = new Javalin(state);
app.jettyServer.getValue(); // initialize server if no plugin already did
return app;
}
/**
* Creates and starts a new instance with the user provided configuration.
*
* @param config configuration consumer accepting {@link JavalinConfig}
* @return running application instance
*/
public static Javalin start(Consumer<JavalinConfig> config) {
return create(config).start();
}
// Get JavalinServlet (can be attached to other servlet containers)
public Servlet javalinServlet() {
return state.servlet.getValue().getServlet();
}
/**
* Synchronously starts the application instance on the specified port
* with the given host IP to bind to.
*
* @param host The host IP to bind to
* @param port to run on
* @return running application instance.
* @see Javalin#create()
* @see Javalin#start()
*/
public Javalin start(String host, int port) {
state.jetty.host = host;
state.jetty.port = port;
jettyServer.getValue().start();
return this;
}
/**
* Synchronously starts the application instance on the specified port.
* Use port 0 to start the application instance on a random available port.
*
* @param port to run on
* @return running application instance.
* @see Javalin#create()
* @see Javalin#start()
*/
public Javalin start(int port) {
state.jetty.port = port;
jettyServer.getValue().start();
return this;
}
/**
* Synchronously starts the application instance on the configured port, or on
* the configured ServerConnectors if the Jetty server has been manually
* configured.
* If no port or connector is configured, the instance will start on port 8080.
*
* @return running application instance.
* @see Javalin#create()
*/
public Javalin start() {
jettyServer.getValue().start();
return this;
}
/**
* Synchronously stops the application instance.
*
* @return stopped application instance.
*/
public Javalin stop() {
if (jettyServer.getValue().server().isStopping() || jettyServer.getValue().server().isStopped()) {
return this;
}
jettyServer.getValue().stop();
return this;
}
/**
* Get which port instance is running on
* Mostly useful if you start the instance with port(0) (random port)
*/
public int port() {
return jettyServer.getValue().port();
}
}
================================================
FILE: javalin/src/main/java/io/javalin/apibuilder/ApiBuilder.java
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.apibuilder;
import io.javalin.Javalin;
import io.javalin.http.Handler;
import io.javalin.http.sse.SseClient;
import io.javalin.router.JavalinDefaultRoutingApi;
import io.javalin.security.RouteRole;
import io.javalin.websocket.WsConfig;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.function.Consumer;
/**
* Static methods for route declarations in Javalin
*/
public class ApiBuilder {
private static final ThreadLocal<JavalinDefaultRoutingApi> staticJavalin = new ThreadLocal<>();
private static final ThreadLocal<Deque<String>> pathDeque = ThreadLocal.withInitial(ArrayDeque::new);
/**
* Sets the static Javalin instance (ThreadLocal) used by the ApiBuilder methods.
* This is used internally by {@code config.routes.apiBuilder(EndpointGroup)} to enable
* the static route methods like {@link #get(String, Handler)}, and is exposed publicly
* to allow creation of custom static route methods.
*
* @param javalin the Javalin routing API to use for route registration
*/
public static void setStaticJavalin(@NotNull JavalinDefaultRoutingApi javalin) {
staticJavalin.set(javalin);
}
/**
* Clears the static Javalin instance (ThreadLocal) from the current thread.
*
* @see #setStaticJavalin(JavalinDefaultRoutingApi)
*/
public static void clearStaticJavalin() {
staticJavalin.remove();
}
/**
* Prefixes all handlers defined in its scope with the specified path.
* All paths are normalized, so you can call both
* path("/path") or path("path") depending on your preference
*/
public static void path(@NotNull String path, @NotNull EndpointGroup endpointGroup) {
path = path.startsWith("/") ? path : "/" + path;
pathDeque.get().addLast(path);
endpointGroup.addEndpoints();
pathDeque.get().removeLast();
}
public static String prefixPath(@NotNull String path) {
if (!path.equals("*")) {
path = (path.startsWith("/") || path.isEmpty()) ? path : "/" + path;
}
return String.join("", pathDeque.get()) + path;
}
public static JavalinDefaultRoutingApi staticInstance() {
JavalinDefaultRoutingApi javalin = staticJavalin.get();
if (javalin == null) {
throw new IllegalStateException("The static API can only be used within a routes() call.");
}
return javalin;
}
// ********************************************************************************************
// HTTP verbs
// ********************************************************************************************
/**
* Adds a GET request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void get(@NotNull String path, @NotNull Handler handler) {
staticInstance().get(prefixPath(path), handler);
}
/**
* Adds a GET request handler with the given roles for the specified path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void get(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().get(prefixPath(path), handler, roles);
}
/**
* Adds a GET request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void get(@NotNull Handler handler) {
staticInstance().get(prefixPath(""), handler);
}
/**
* Adds a GET request handler with the given roles for the current path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void get(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().get(prefixPath(""), handler, roles);
}
/**
* Adds a POST request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void post(@NotNull String path, @NotNull Handler handler) {
staticInstance().post(prefixPath(path), handler);
}
/**
* Adds a POST request handler with the given roles for the specified path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void post(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().post(prefixPath(path), handler, roles);
}
/**
* Adds a POST request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void post(@NotNull Handler handler) {
staticInstance().post(prefixPath(""), handler);
}
/**
* Adds a QUERY request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a {@code config.routes.apiBuilder(EndpointGroup)}.
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void query(@NotNull String path, @NotNull Handler handler) {
staticInstance().query(prefixPath(path), handler);
}
/**
* Adds a QUERY request handler with the given roles for the specified path to the instance.
* The method can only be called inside a {@code config.routes.apiBuilder(EndpointGroup)}.
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void query(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().query(prefixPath(path), handler, roles);
}
/**
* Adds a QUERY request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a {@code config.routes.apiBuilder(EndpointGroup)}.
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void query(@NotNull Handler handler) {
staticInstance().query(prefixPath(""), handler);
}
/**
* Adds a QUERY request handler with the given roles for the current path to the instance.
* The method can only be called inside a {@code config.routes.apiBuilder(EndpointGroup)}.
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void query(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().query(prefixPath(""), handler, roles);
}
/**
* Adds a POST request handler with the given roles for the current path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void post(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().post(prefixPath(""), handler, roles);
}
/**
* Adds a PUT request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void put(@NotNull String path, @NotNull Handler handler) {
staticInstance().put(prefixPath(path), handler);
}
/**
* Adds a PUT request handler with the given roles for the specified path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void put(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().put(prefixPath(path), handler, roles);
}
/**
* Adds a PUT request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void put(@NotNull Handler handler) {
staticInstance().put(prefixPath(""), handler);
}
/**
* Adds a PUT request handler with the given roles for the current path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void put(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().put(prefixPath(""), handler, roles);
}
/**
* Adds a PATCH request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void patch(@NotNull String path, @NotNull Handler handler) {
staticInstance().patch(prefixPath(path), handler);
}
/**
* Adds a PATCH request handler with the given roles for the specified path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void patch(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().patch(prefixPath(path), handler, roles);
}
/**
* Adds a PATCH request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void patch(@NotNull Handler handler) {
staticInstance().patch(prefixPath(""), handler);
}
/**
* Adds a PATCH request handler with the given roles for the current path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void patch(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().patch(prefixPath(""), handler, roles);
}
/**
* Adds a DELETE request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void delete(@NotNull String path, @NotNull Handler handler) {
staticInstance().delete(prefixPath(path), handler);
}
/**
* Adds a DELETE request handler with the given roles for the specified path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void delete(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().delete(prefixPath(path), handler, roles);
}
/**
* Adds a DELETE request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void delete(@NotNull Handler handler) {
staticInstance().delete(prefixPath(""), handler);
}
/**
* Adds a DELETE request handler with the given roles for the current path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void delete(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().delete(prefixPath(""), handler, roles);
}
/**
* Adds a HEAD request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void head(@NotNull String path, @NotNull Handler handler) {
staticInstance().head(prefixPath(path), handler);
}
/**
* Adds a HEAD request handler with the given roles for the specified path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void head(@NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().head(prefixPath(path), handler, roles);
}
/**
* Adds a HEAD request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void head(@NotNull Handler handler) {
staticInstance().head(prefixPath(""), handler);
}
/**
* Adds a HEAD request handler with the given roles for the current path to the instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void head(@NotNull Handler handler, @NotNull RouteRole... roles) {
staticInstance().head(prefixPath(""), handler, roles);
}
// ********************************************************************************************
// Before/after handlers (filters)
// ********************************************************************************************
/**
* Adds a BEFORE request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#before-handlers">Handlers in docs</a>
*/
public static void before(@NotNull String path, @NotNull Handler handler) {
staticInstance().before(prefixPath(path), handler);
}
/**
* Adds a BEFORE request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void before(@NotNull Handler handler) {
staticInstance().before(prefixPath("*"), handler);
}
/**
* Adds a BEFORE_MATCHED request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#before-handlers">Handlers in docs</a>
*/
public static void beforeMatched(@NotNull String path, @NotNull Handler handler) {
staticInstance().beforeMatched(prefixPath(path), handler);
}
/**
* Adds a BEFORE_MATCHED request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void beforeMatched(@NotNull Handler handler) {
staticInstance().beforeMatched(prefixPath("*"), handler);
}
/**
* Adds an AFTER request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#before-handlers">Handlers in docs</a>
*/
public static void after(@NotNull String path, @NotNull Handler handler) {
staticInstance().after(prefixPath(path), handler);
}
/**
* Adds a AFTER request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void after(@NotNull Handler handler) {
staticInstance().after(prefixPath("*"), handler);
}
/**
* Adds a AFTER_MATCHED request handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#before-handlers">Handlers in docs</a>
*/
public static void afterMatched(@NotNull String path, @NotNull Handler handler) {
staticInstance().afterMatched(prefixPath(path), handler);
}
/**
* Adds a AFTER_MATCHED request handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void afterMatched(@NotNull Handler handler) {
staticInstance().afterMatched(prefixPath("*"), handler);
}
// ********************************************************************************************
// WebSocket
// ********************************************************************************************
/**
* Adds a WebSocket handler on the specified path.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#websockets">WebSockets in docs</a>
*/
public static void ws(@NotNull String path, @NotNull Consumer<WsConfig> ws) {
staticInstance().ws(prefixPath(path), ws);
}
/**
* Adds a WebSocket handler with the given roles for the specified path.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#websockets">WebSockets in docs</a>
*/
public static void ws(@NotNull String path, @NotNull Consumer<WsConfig> ws, @NotNull RouteRole... roles) {
staticInstance().ws(prefixPath(path), ws, roles);
}
/**
* Adds a WebSocket handler on the current path.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#websockets">WebSockets in docs</a>
*/
public static void ws(@NotNull Consumer<WsConfig> ws) {
staticInstance().ws(prefixPath(""), ws);
}
/**
* Adds a WebSocket handler with the given roles for the current path.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#websockets">WebSockets in docs</a>
*/
public static void ws(@NotNull Consumer<WsConfig> ws, @NotNull RouteRole... roles) {
staticInstance().ws(prefixPath(""), ws, roles);
}
/**
* Adds a WebSocket before handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*/
public static void wsBefore(@NotNull String path, @NotNull Consumer<WsConfig> wsConfig) {
staticInstance().wsBefore(prefixPath(path), wsConfig);
}
/**
* Adds a WebSocket before handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*/
public static void wsBefore(@NotNull Consumer<WsConfig> wsConfig) {
staticInstance().wsBefore(prefixPath("*"), wsConfig);
}
/**
* Adds a WebSocket after handler for the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*/
public static void wsAfter(@NotNull String path, @NotNull Consumer<WsConfig> wsConfig) {
staticInstance().wsAfter(prefixPath(path), wsConfig);
}
/**
* Adds a WebSocket after handler for the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*/
public static void wsAfter(@NotNull Consumer<WsConfig> wsConfig) {
staticInstance().wsAfter(prefixPath("*"), wsConfig);
}
// ********************************************************************************************
// Server-sent events
// ********************************************************************************************
public static void sse(@NotNull String path, @NotNull Consumer<SseClient> client) {
staticInstance().sse(prefixPath(path), client);
}
public static void sse(@NotNull String path, @NotNull Consumer<SseClient> client, @NotNull RouteRole... roles) {
staticInstance().sse(prefixPath(path), client, roles);
}
public static void sse(@NotNull Consumer<SseClient> client) {
staticInstance().sse(prefixPath(""), client);
}
public static void sse(@NotNull Consumer<SseClient> client, @NotNull RouteRole... roles) {
staticInstance().sse(prefixPath(""), client, roles);
}
// ********************************************************************************************
// CrudHandler
// ********************************************************************************************
/**
* Adds a CrudHandler handler to the current path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void crud(@NotNull CrudHandler crudHandler) {
crud("", crudHandler, new RouteRole[0]);
}
/**
* Adds a CrudHandler handler to the current path with the given roles to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see <a href="https://javalin.io/documentation#handlers">Handlers in docs</a>
*/
public static void crud(@NotNull CrudHandler crudHandler, @NotNull RouteRole... roles) {
crud("", crudHandler, roles);
}
/**
* Adds a CrudHandler handler to the specified path to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see CrudHandler
*/
public static void crud(@NotNull String path, @NotNull CrudHandler crudHandler) {
crud(path, crudHandler, new RouteRole[0]);
}
/**
* Adds a CrudHandler handler to the specified path with the given roles to the {@link Javalin} instance.
* The method can only be called inside a config.routes.apiBuilder(EndpointGroup).
*
* @see CrudHandler
*/
public static void crud(@NotNull String path, @NotNull CrudHandler crudHandler, @NotNull RouteRole... roles) {
String fullPath = prefixPath(path);
String[] subPaths = Arrays.stream(fullPath.split("/")).filter(it -> !it.isEmpty()).toArray(String[]::new);
if (subPaths.length < 2) {
throw new IllegalArgumentException("CrudHandler requires a path like '/resource/{resource-id}'");
}
String resourceId = subPaths[subPaths.length - 1];
if (!(resourceId.startsWith("{") && resourceId.endsWith("}"))) {
throw new IllegalArgumentException("CrudHandler requires a path-parameter at the end of the provided path, e.g. '/users/{user-id}'");
}
String resourceBase = subPaths[subPaths.length - 2];
if (resourceBase.startsWith("{") || resourceBase.startsWith("<") || resourceBase.endsWith("}") || resourceBase.endsWith(">")) {
throw new IllegalArgumentException("CrudHandler requires a resource base at the beginning of the provided path, e.g. '/users/{user-id}'");
}
staticInstance().get(fullPath, ctx -> crudHandler.getOne(ctx, ctx.pathParam(resourceId)), roles);
staticInstance().get(fullPath.replace(resourceId, ""), crudHandler::getAll, roles);
staticInstance().post(fullPath.replace(resourceId, ""), crudHandler::create, roles);
staticInstance().patch(fullPath, ctx -> crudHandler.update(ctx, ctx.pathParam(resourceId)), roles);
staticInstance().delete(fullPath, ctx -> crudHandler.delete(ctx, ctx.pathParam(resourceId)), roles);
}
}
================================================
FILE: javalin/src/main/java/io/javalin/apibuilder/CrudHandler.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.apibuilder
import io.javalin.http.Context
/**
* The CrudHandler is an interface for handling the five most
* common CRUD operations. It's only available through the ApiBuilder.
*
* @see ApiBuilder
*/
interface CrudHandler {
fun getAll(ctx: Context)
fun getOne(ctx: Context, resourceId: String)
fun create(ctx: Context)
fun update(ctx: Context, resourceId: String)
fun delete(ctx: Context, resourceId: String)
}
================================================
FILE: javalin/src/main/java/io/javalin/apibuilder/EndpointGroup.java
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.apibuilder;
@FunctionalInterface
public interface EndpointGroup {
void addEndpoints();
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/Brotli.kt
================================================
package io.javalin.compression
/** Configuration for Brotli compression
* @param level Compression level. Higher yields better (but slower) compression. Range 0..11, default = 4 */
class Brotli(val level: Int = 4) {
init {
require(level in 0..11) { "Valid range for parameter level is 0 to 11" }
}
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/Brotli4jCompressor.kt
================================================
package io.javalin.compression
import com.aayushatharva.brotli4j.encoder.BrotliOutputStream
import com.aayushatharva.brotli4j.encoder.Encoder
import java.io.OutputStream
/** @param level Compression level. Higher yields better (but slower) compression. Range 0..11, default = 4 */
class Brotli4jCompressor(val level: Int) : Compressor {
init {
require(level in 0..11) { "Valid range for parameter level is 0 to 11" }
}
override fun encoding(): String = CompressionType.BR.typeName
override fun extension(): String = CompressionType.BR.extension
override fun compress(out: OutputStream): OutputStream = LeveledBrotli4jStream(out, level)
}
class LeveledBrotli4jStream(out: OutputStream, level: Int) :
BrotliOutputStream(out, Encoder.Parameters().setQuality(level))
================================================
FILE: javalin/src/main/java/io/javalin/compression/CompressedStream.kt
================================================
package io.javalin.compression
import io.javalin.http.Context
import io.javalin.http.Header
import jakarta.servlet.ServletOutputStream
import jakarta.servlet.WriteListener
import java.io.OutputStream
internal class CompressedOutputStream(
val minSizeForCompression: Int,
val compression: CompressionStrategy,
val ctx: Context,
) : ServletOutputStream() {
private val originStream = ctx.res().outputStream
private var compressedStream: OutputStream? = null
private var isCompressionDecisionMade = false
private fun maybeCreateCompressionStreamOnFirstWrite(length: Int) {
if (!isCompressionDecisionMade) {
val isCompressionAllowed = !ctx.res().containsHeader(Header.CONTENT_ENCODING) &&
compression.allowsForCompression(ctx.res().contentType)
val isCompressionDesired = length >= minSizeForCompression
if (isCompressionAllowed && isCompressionDesired) {
compression.findMatchingCompressor(ctx.header(Header.ACCEPT_ENCODING) ?: "")?.also {
this.compressedStream = it.compress(originStream)
ctx.header(Header.CONTENT_ENCODING, it.encoding())
}
}
isCompressionDecisionMade = true
}
}
override fun write(bytes: ByteArray, offset: Int, length: Int) {
maybeCreateCompressionStreamOnFirstWrite(length)
(compressedStream ?: originStream).write(bytes, offset, length)
}
override fun write(byte: Int) {
maybeCreateCompressionStreamOnFirstWrite(1)
(compressedStream ?: originStream).write(byte)
}
override fun setWriteListener(writeListener: WriteListener?) = originStream.setWriteListener(writeListener)
override fun isReady(): Boolean = originStream.isReady
override fun close() {
compressedStream?.close()
}
}
private fun CompressionStrategy.allowsForCompression(contentType: String?): Boolean =
contentType == null || allowedMimeTypes.contains(contentType) || excludedMimeTypes.none { excluded ->
contentType.contains(excluded, ignoreCase = true)
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/CompressionStrategy.kt
================================================
package io.javalin.compression
import com.aayushatharva.brotli4j.Brotli4jLoader
import io.javalin.util.CoreDependency
import io.javalin.util.DependencyUtil
import io.javalin.util.JavalinLogger
import io.javalin.util.Util
/**
* This class is a settings container for Javalin's content compression.
*
* It is used by the CompressedOutputStream and JettyPrecompressingResourceHandler to determine the encoding and parameters that should be used when compressing a response.
*
* @see io.javalin.compression.CompressedOutputStream
* @see io.javalin.jetty.JettyPrecompressingResourceHandler
*
* @param brotli instance of Brotli config, default = null
* @param gzip instance of Gzip config, default = null
* @param zstd instance of Zstd config, default = null
*/
class CompressionStrategy(brotli: Brotli? = null, gzip: Gzip? = null, zstd: Zstd? = null) {
/**
* Backward compatibility constructor for existing code
*/
constructor(brotli: Brotli?, gzip: Gzip?) : this(brotli, gzip, null)
companion object {
@JvmField
val NONE = CompressionStrategy()
@JvmField
val GZIP = CompressionStrategy(null, Gzip())
// Check if the dependency is present
fun brotli4jPresent() = Util.classExists(CoreDependency.BROTLI4J.testClass)
// Check if the native libraries are available
fun brotli4jAvailable() = try {
Brotli4jLoader.isAvailable()
} catch (t: Throwable) {
false
}
/** @returns true if brotli is can be used */
fun brotliImplAvailable() = brotli4jPresent() && brotli4jAvailable()
// Check if the zstd-jni dependency is present
fun zstdJniPresent() = Util.classExists(CoreDependency.ZSTD_JNI.testClass)
// Check if the zstd native libraries are available
fun zstdJniAvailable() = try {
// Attempt to access Zstd class which triggers native library loading
com.github.luben.zstd.Zstd.defaultCompressionLevel()
true
} catch (t: Throwable) {
false
}
/** @returns true if zstd can be used */
fun zstdImplAvailable() = zstdJniPresent() && zstdJniAvailable()
}
val compressors: List<Compressor>
init {
val comp: MutableList<Compressor> = mutableListOf()
//Enabling brotli requires special handling since brotli is platform dependent
if (brotli != null) tryLoadBrotli(brotli)?.let { comp.add(it) }
//Enabling zstd requires special handling since zstd is platform dependent
if (zstd != null) tryLoadZstd(zstd)?.let { comp.add(it) }
if (gzip != null) comp.add(GzipCompressor(gzip.level))
compressors = comp.toList()
}
/** 1500 is the size of a packet, compressing responses smaller than this serves no purpose */
var defaultMinSizeForCompression = 1500
/** these mime types will always be allowed */
var allowedMimeTypes = listOf(
"image/svg+xml" // we need to allow svg explicitly, because images in general are excluded
)
/** these mime types will be processed using NONE compression strategy */
var excludedMimeTypes = listOf(
"image/",
"audio/",
"video/",
"application/compress",
"application/zip",
"application/gzip",
"application/bzip2",
"application/brotli",
"application/x-xz",
"application/x-rar-compressed"
)
var preferredCompressors: List<CompressionType> = listOf()
/**
* When enabling Brotli, we try loading the jvm-brotli native libraries first.
* If this fails, we keep Brotli disabled and warn the user.
*/
private fun tryLoadBrotli(brotli: Brotli): Compressor? {
if (!brotli4jPresent()) {
throw IllegalStateException(DependencyUtil.missingDependencyMessage(CoreDependency.BROTLI4J))
}
return when {
Brotli4jLoader.isAvailable() -> return Brotli4jCompressor(brotli.level)
else -> {
JavalinLogger.warn(
"""|
|Failed to enable Brotli compression, because the brotli4j native library couldn't be loaded.
|brotli4j is currently only supported on Windows, Linux and Mac OSX.
|If you are running Javalin on a supported system, but are still getting this error,
|try re-importing your Maven and/or Gradle dependencies. If that doesn't resolve it,
|please create an issue at https://github.com/javalin/javalin/
|---------------------------------------------------------------
|If you still want compression, please ensure GZIP is enabled!
|---------------------------------------------------------------""".trimMargin()
)
null
}
}
}
/**
* When enabling Zstd, we try loading the zstd-jni native libraries first.
* If this fails, we keep Zstd disabled and warn the user.
*/
private fun tryLoadZstd(zstd: Zstd): Compressor? {
if (!zstdJniPresent()) {
throw IllegalStateException(DependencyUtil.missingDependencyMessage(CoreDependency.ZSTD_JNI))
}
return when {
zstdJniAvailable() -> return ZstdCompressor(zstd.level)
else -> {
JavalinLogger.warn(
"""|
|Failed to enable Zstd compression, because the zstd-jni native library couldn't be loaded.
|zstd-jni is currently only supported on Windows, Linux and Mac OSX.
|If you are running Javalin on a supported system, but are still getting this error,
|try re-importing your Maven and/or Gradle dependencies. If that doesn't resolve it,
|please create an issue at https://github.com/javalin/javalin/
|---------------------------------------------------------------
|If you still want compression, please ensure GZIP is enabled!
|---------------------------------------------------------------""".trimMargin()
)
null
}
}
}
private fun getPreferredCompressorForSupportedCompressors(supportedCompressors: List<String>): Compressor? {
for (preferredCompressor in preferredCompressors) {
if (supportedCompressors.any { it.equals(preferredCompressor.typeName, ignoreCase = true) }) {
val compressor = compressors.forType(preferredCompressor.typeName)
if (compressor != null) {
return compressor
}
}
}
return null;
}
fun findMatchingCompressor(encodingHeaderValue: String): Compressor? {
val supportedCompressors = encodingHeaderValue
.split(",")
.map { it.trim() }
val compressor = getPreferredCompressorForSupportedCompressors(supportedCompressors)
if (compressor != null) {
return compressor
}
return supportedCompressors.firstNotNullOfOrNull { compressors.forType(it) }
}
}
fun List<Compressor>.forType(type: String) = this.firstOrNull { it.encoding().equals(type, ignoreCase = true) }
================================================
FILE: javalin/src/main/java/io/javalin/compression/CompressionType.kt
================================================
package io.javalin.compression
enum class CompressionType(val typeName: String, val extension: String) {
GZIP("gzip", ".gz"),
BR("br", ".br"),
ZSTD("zstd", ".zst"),
NONE("", "");
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/Compressor.kt
================================================
package io.javalin.compression
import java.io.OutputStream
/** A compressor is used to compress an output stream */
interface Compressor {
/** The content encoding for this compressor (e.g. "gzip")
* [MDN Content-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding)
* @return the content encoding (case-insensitive) */
fun encoding(): String
/** @return the file extension for this compressor (empty string if none) */
fun extension(): String = ""
/** @param out the output stream to compress
* @return the compressed output stream */
fun compress(out: OutputStream): OutputStream
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/Gzip.kt
================================================
package io.javalin.compression
/** Configuration for Gzip compression
* @param level Compression level. Higher yields better (but slower) compression. Range 0..9, default = 6 */
class Gzip(val level: Int = 6) {
init {
require(level in 0..9) { "Valid range for parameter level is 0 to 9" }
}
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/GzipCompressor.kt
================================================
package io.javalin.compression
import java.io.OutputStream
import java.util.zip.GZIPOutputStream
/** @param level Compression level. Higher yields better (but slower) compression. Range 0..9, default = 6 */
class GzipCompressor(val level: Int) : Compressor {
init {
require(level in 0..9) { "Valid range for parameter level is 0 to 9" }
}
override fun encoding() = CompressionType.GZIP.typeName
override fun extension() = CompressionType.GZIP.extension
override fun compress(out: OutputStream) = LeveledGzipStream(out, level)
}
class LeveledGzipStream(out: OutputStream, level: Int) : GZIPOutputStream(out) {
init {
this.def.setLevel(level)
}
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/Zstd.kt
================================================
package io.javalin.compression
/** Configuration for Zstd compression
* @param level Compression level. Higher yields better (but slower) compression. Range 0..22, default = 3 */
class Zstd(val level: Int = 3) {
init {
require(level in 0..22) { "Valid range for parameter level is 0 to 22" }
}
}
================================================
FILE: javalin/src/main/java/io/javalin/compression/ZstdCompressor.kt
================================================
package io.javalin.compression
import com.github.luben.zstd.ZstdOutputStream
import java.io.OutputStream
/** @param level Compression level. Higher yields better (but slower) compression. Range 0..22, default = 3 */
class ZstdCompressor(val level: Int) : Compressor {
init {
require(level in 0..22) { "Valid range for parameter level is 0 to 22" }
}
override fun encoding(): String = CompressionType.ZSTD.typeName
override fun extension(): String = CompressionType.ZSTD.extension
override fun compress(out: OutputStream): OutputStream = ZstdOutputStream(out, level)
}
================================================
FILE: javalin/src/main/java/io/javalin/config/AppDataManager.kt
================================================
package io.javalin.config
data class Key<T>(val id: String)
class KeyAlreadyExistsException(key: Key<*>) : IllegalStateException("Key '$key' already exists")
class NoValueForKeyException(key: Key<*>) : IllegalStateException("No value for key '$key'")
class AppDataManager {
private val data: MutableMap<Key<*>, Any?> = mutableMapOf()
fun <T> register(key: Key<T>, value: T) {
if (data.containsKey(key)) {
throw KeyAlreadyExistsException(key)
}
data[key] = value
}
fun <T> registerIfAbsent(key: Key<T>, value: T) {
data.putIfAbsent(key, value)
}
fun <T> get(key: Key<T>): T {
return data[key] as T? ?: throw NoValueForKeyException(key)
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/BundledPluginsConfig.kt
================================================
package io.javalin.config
import io.javalin.plugin.bundled.BasicAuthPlugin
import io.javalin.plugin.bundled.CorsPlugin
import io.javalin.plugin.bundled.CorsPluginConfig
import io.javalin.plugin.bundled.DevLoggingPlugin
import io.javalin.plugin.bundled.GlobalHeadersConfig
import io.javalin.plugin.bundled.GlobalHeadersPlugin
import io.javalin.plugin.bundled.HttpAllowedMethodsPlugin
import io.javalin.plugin.bundled.RedirectToLowercasePathPlugin
import io.javalin.plugin.bundled.RouteOverviewPlugin
import io.javalin.plugin.bundled.SslRedirectPlugin
import io.javalin.security.RouteRole
import java.util.function.Consumer
/**
* Configuration to enable bundled plugins or add custom ones.
*
* @see [JavalinState.bundledPlugins]
*/
class BundledPluginsConfig(private val cfg: JavalinState) {
/**
* Enables the RouteOverview plugin.
* @param path the path from which the route overview should be visible
* @param roles the roles restricting who can access the route overview
* @see [RouteOverviewPlugin]
*/
fun enableRouteOverview(path: String, vararg roles: RouteRole = emptyArray()) =
cfg.registerPlugin(RouteOverviewPlugin {
it.path = path
it.roles = roles
})
/**
* Enables the Basic Authentication plugin.
* @see [BasicAuthPlugin]
*/
fun enableBasicAuth(username: String, password: String) =
cfg.registerPlugin(BasicAuthPlugin {
it.username = username
it.password = password
})
/**
* Enables the Global Headers plugin.
* @see [GlobalHeadersPlugin]
*/
fun enableGlobalHeaders(globalHeadersConfig: Consumer<GlobalHeadersConfig>) = cfg.registerPlugin(GlobalHeadersPlugin(globalHeadersConfig))
/**
* Enables the Cors Plugin.
* @see [GlobalHeadersPlugin]
*/
fun enableCors(userConfig: Consumer<CorsPluginConfig>) = cfg.registerPlugin(CorsPlugin(userConfig))
/** Enables the HttpAllowedMethodsPlugin, automatically handling the Options request on configured routes. */
fun enableHttpAllowedMethodsOnRoutes() = cfg.registerPlugin(HttpAllowedMethodsPlugin())
/** Enables the development debugging logger plugin. */
fun enableDevLogging() = cfg.registerPlugin(DevLoggingPlugin())
/** Enables the development debugging logger plugin with the specified config */
fun enableDevLogging(userConfig: Consumer<DevLoggingPlugin.Config>) = cfg.registerPlugin(DevLoggingPlugin(userConfig))
/** Enables the RedirectToLowercasePath plugin. */
fun enableRedirectToLowercasePaths() = cfg.registerPlugin(RedirectToLowercasePathPlugin())
/** Enables the SSL Redirects plugin, which redirect any http request to https. Note it must be the first plugin enabled to properly handle all requests.*/
fun enableSslRedirects() = cfg.registerPlugin(SslRedirectPlugin())
}
================================================
FILE: javalin/src/main/java/io/javalin/config/ConcurrencyConfig.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.config
import io.javalin.http.util.AsyncExecutor
import io.javalin.util.ConcurrencyUtil
import io.javalin.util.javalinLazy
class ConcurrencyConfig {
@JvmField var useVirtualThreads = false
@JvmField var executor = javalinLazy { AsyncExecutor(ConcurrencyUtil.executorService("JavalinDefaultAsyncThreadPool", useVirtualThreads)) }
}
================================================
FILE: javalin/src/main/java/io/javalin/config/ContextResolverConfig.kt
================================================
package io.javalin.config
import io.javalin.http.Context
import io.javalin.http.Header
/**
* Configure the implementation for Context functions.
*
* @see [JavalinState.contextResolver]
*/
class ContextResolverConfig {
companion object {
internal val ContextResolverKey = Key<ContextResolverConfig>("javalin-context-resolver")
}
// @formatter:off
/** The IP address resolver (default: reads the `remoteAddr` part of the request) */
@JvmField var ip: (Context) -> String = { it.req().remoteAddr }
/** The host resolver (default: reads the `Host` header). */
@JvmField var host: (Context) -> String? = { it.header(Header.HOST) }
/** The scheme resolver (default: reads the `scheme` part of the request). */
@JvmField var scheme: (Context) -> String = { it.req().scheme }
/** The URL resolver (default: reads the `requestUrl` part of the request). */
@JvmField var url: (Context) -> String = { it.req().requestURL.toString() }
/** The full URL resolver (default: reads the url with its query string). */
@JvmField var fullUrl: (Context) -> String = { it.url() + if (it.queryString() != null) "?" + it.queryString() else "" }
// @formatter:on
}
================================================
FILE: javalin/src/main/java/io/javalin/config/EventConfig.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.config;
import io.javalin.event.EventManager
import io.javalin.event.HandlerMetaInfo
import io.javalin.event.JavalinLifecycleEvent.SERVER_STARTED
import io.javalin.event.JavalinLifecycleEvent.SERVER_STARTING
import io.javalin.event.JavalinLifecycleEvent.SERVER_START_FAILED
import io.javalin.event.JavalinLifecycleEvent.SERVER_STOPPED
import io.javalin.event.JavalinLifecycleEvent.SERVER_STOPPING
import io.javalin.event.JavalinLifecycleEvent.SERVER_STOP_FAILED
import io.javalin.event.LifecycleEventListener
import io.javalin.event.WsHandlerMetaInfo
import io.javalin.http.Handler
import java.util.function.Consumer
/**
* Configures the events' listener.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.events]
*/
class EventConfig(private val cfg: JavalinState) {
/** Adds a callback to react on the Server Starting event. */
fun serverStarting(lifecycleEventListener: LifecycleEventListener) = eventManager.addLifecycleEvent(SERVER_STARTING, lifecycleEventListener)
/** Adds a callback to react on the Server Started event. */
fun serverStarted(lifecycleEventListener: LifecycleEventListener) = eventManager.addLifecycleEvent(SERVER_STARTED, lifecycleEventListener)
/** Adds a callback to react on the Server Start Failed event. */
fun serverStartFailed(lifecycleEventListener: LifecycleEventListener) = eventManager.addLifecycleEvent(SERVER_START_FAILED, lifecycleEventListener)
/** Adds a callback to react on the Server Stop Failed event. */
fun serverStopFailed(lifecycleEventListener: LifecycleEventListener) = eventManager.addLifecycleEvent(SERVER_STOP_FAILED, lifecycleEventListener)
/** Adds a callback to react on the Server Stopping event. */
fun serverStopping(lifecycleEventListener: LifecycleEventListener) = eventManager.addLifecycleEvent(SERVER_STOPPING, lifecycleEventListener)
/** Adds a callback to react on the Server Stopped event. */
fun serverStopped(lifecycleEventListener: LifecycleEventListener) = eventManager.addLifecycleEvent(SERVER_STOPPED, lifecycleEventListener)
/** Adds a callback to react when a [Handler] is added. */
fun handlerAdded(callback: Consumer<HandlerMetaInfo>) {
eventManager.handlerAddedHandlers.add(callback);
}
/** Adds a callback to react when a websocket Handler is added. */
fun wsHandlerAdded(callback: Consumer<WsHandlerMetaInfo>) {
eventManager.wsHandlerAddedHandlers.add(callback);
}
private val eventManager: EventManager
get() = cfg.eventManager
}
================================================
FILE: javalin/src/main/java/io/javalin/config/HttpConfig.kt
================================================
package io.javalin.config
import io.javalin.compression.CompressionStrategy
import io.javalin.http.ContentType
/**
* Configuration for the HTTP layer.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.http]
*/
class HttpConfig() {
//@formatter:off
@JvmField var generateEtags = false
@JvmField var prefer405over404 = false
@JvmField var strictContentTypes = false
@JvmField var maxRequestSize = 1_000_000L // increase this or use inputstream to handle large requests
@JvmField var responseBufferSize: Int? = null
@JvmField var defaultContentType = ContentType.PLAIN
@JvmField var asyncTimeout = 0L
@JvmField var compressionStrategy = CompressionStrategy.GZIP
//@formatter:on
}
================================================
FILE: javalin/src/main/java/io/javalin/config/JavalinConfig.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.config
import io.javalin.Javalin
import io.javalin.http.servlet.JavalinServletContext
import io.javalin.http.servlet.TaskInitializer
import io.javalin.http.staticfiles.ResourceHandler
import io.javalin.json.JsonMapper
import io.javalin.plugin.Plugin
import io.javalin.rendering.FileRenderer
/**
* Public-facing configuration API exposed to users in [Javalin.create].
* This class provides a safe subset of configuration options, hiding internal APIs.
*
* For advanced/dangerous configuration options, use [Javalin.unsafe] to access [JavalinState] directly.
*
* @see JavalinState
*/
class JavalinConfig internal constructor(
/**
* Advanced/unsafe API providing access to internal Javalin configuration.
* This exposes powerful but potentially dangerous APIs. Use with caution.
*/
@JvmField val unsafe: JavalinState
) {
// CORE CONFIGS - HTTP, routing, and server
@JvmField val http = unsafe.http
@JvmField val router = unsafe.router
@JvmField val jetty = unsafe.jetty
// FEATURE CONFIGS - Static files, SPAs, and routes
@JvmField val staticFiles = unsafe.staticFiles
@JvmField val spaRoot = unsafe.spaRoot
@JvmField val routes = unsafe.routes
// CROSS-CUTTING CONFIGS - Validation, context resolution, logging, plugins, events
@JvmField val validation = unsafe.validation
@JvmField val contextResolver = unsafe.contextResolver
@JvmField val requestLogger = unsafe.requestLogger
@JvmField val bundledPlugins = unsafe.bundledPlugins
@JvmField val events = unsafe.events
// MISC SETTINGS - General application-level settings
@JvmField val startup = unsafe.startup
@JvmField val concurrency = unsafe.concurrency
// PUBLIC METHODS - Delegated to unsafe
fun requestLifeCycle(vararg requestLifecycle: TaskInitializer<JavalinServletContext>) = unsafe.requestLifeCycle(*requestLifecycle)
fun jsonMapper(jsonMapper: JsonMapper) = unsafe.jsonMapper(jsonMapper)
fun fileRenderer(fileRenderer: FileRenderer) = unsafe.fileRenderer(fileRenderer)
fun resourceHandler(resourceHandler: ResourceHandler) = unsafe.resourceHandler(resourceHandler)
fun <CFG> registerPlugin(plugin: Plugin<CFG>) = unsafe.registerPlugin(plugin)
fun <T> appData(key: Key<T>, value: T) = unsafe.appData(key, value)
}
================================================
FILE: javalin/src/main/java/io/javalin/config/JavalinState.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.config
import io.javalin.Javalin
import io.javalin.config.ContextResolverConfig.Companion.ContextResolverKey
import io.javalin.event.EventManager
import io.javalin.http.RequestLogger
import io.javalin.http.SinglePageHandler
import io.javalin.http.servlet.DefaultTasks
import io.javalin.http.servlet.JavalinServlet
import io.javalin.http.servlet.JavalinServletContext
import io.javalin.http.servlet.MaxRequestSize.MaxRequestSizeKey
import io.javalin.http.servlet.ServletEntry
import io.javalin.http.servlet.TaskInitializer
import io.javalin.http.staticfiles.ResourceHandler
import io.javalin.http.util.AsyncExecutor.Companion.AsyncExecutorKey
import io.javalin.jetty.JettyUtil.createJettyServletWithWebsocketsIfAvailable
import io.javalin.json.JavalinJackson
import io.javalin.json.JsonMapper
import io.javalin.plugin.Plugin
import io.javalin.plugin.PluginManager
import io.javalin.rendering.FileRenderer
import io.javalin.rendering.FileRenderer.Companion.FileRendererKey
import io.javalin.rendering.NotImplementedRenderer
import io.javalin.router.InternalRouter
import io.javalin.util.javalinLazy
import io.javalin.validation.Validation
import io.javalin.validation.Validation.Companion.ValidationKey
import io.javalin.validation.Validation.Companion.addValidationExceptionMapper
import io.javalin.websocket.WsConfig
import io.javalin.websocket.WsRouter
import java.util.function.Consumer
/**
* Complete Javalin configuration state containing both public and internal APIs.
*
* Users access the safe public API through [JavalinConfig] in [Javalin.create].
* Internal APIs and power users can access this class directly through [Javalin.unsafe].
*
* @see JavalinConfig
* @see [Javalin.create]
*/
class JavalinState {
//@formatter:off
// CORE CONFIGS - HTTP, routing, and server
@JvmField val http = HttpConfig()
@JvmField val router = RouterConfig()
@JvmField val jetty = JettyConfig(this)
// FEATURE CONFIGS - Static files, SPAs, and routes
@JvmField val staticFiles = StaticFilesConfig(this)
@JvmField val spaRoot = SpaRootConfig(this)
@JvmField val routes = RoutesConfig(this)
// CROSS-CUTTING CONFIGS - Validation, context resolution, logging, plugins, events
@JvmField val validation = ValidationConfig()
@JvmField val contextResolver = ContextResolverConfig()
@JvmField val requestLogger = RequestLoggerConfig(this)
@JvmField val bundledPlugins = BundledPluginsConfig(this)
@JvmField val events = EventConfig(this)
// MISC SETTINGS - General application-level settings
@JvmField val startup = StartupConfig()
@JvmField val concurrency = ConcurrencyConfig()
// INTERNAL CONFIG API
@JvmField val eventManager = EventManager()
@JvmField val wsRouter = WsRouter(router)
@JvmField var internalRouter = InternalRouter(wsRouter, eventManager, router, jetty)
@JvmField var jsonMapper: Lazy<JsonMapper> = javalinLazy { JavalinJackson(null, concurrency.useVirtualThreads) }
@JvmField var appDataManager = AppDataManager()
@JvmField var pluginManager = PluginManager(this)
@JvmField var httpRequestLoggers: MutableList<RequestLogger> = mutableListOf()
@JvmField var wsRequestLogger: WsConfig? = null
@JvmField var resourceHandler: ResourceHandler? = null
@JvmField var singlePageHandler = SinglePageHandler()
@JvmField var servlet: Lazy<ServletEntry> = javalinLazy { createJettyServletWithWebsocketsIfAvailable(this) ?: ServletEntry(servlet = JavalinServlet(this)) }
@JvmField var jettyInternal = JettyInternalConfig()
@JvmField var servletRequestLifecycle = mutableListOf(
DefaultTasks.BEFORE,
DefaultTasks.BEFORE_MATCHED,
DefaultTasks.HTTP,
DefaultTasks.AFTER_MATCHED,
DefaultTasks.ERROR,
DefaultTasks.AFTER
)
fun requestLifeCycle(vararg lifecycle: TaskInitializer<JavalinServletContext>) {
servletRequestLifecycle = lifecycle.toMutableList()
}
fun resourceHandler(resourceHandler: ResourceHandler) { this.resourceHandler = resourceHandler }
fun jsonMapper(jsonMapper: JsonMapper) { this.jsonMapper = javalinLazy { jsonMapper } }
fun fileRenderer(fileRenderer: FileRenderer) = appData(FileRendererKey, fileRenderer)
fun <CFG> registerPlugin(plugin: Plugin<CFG>): Plugin<CFG> = plugin.also { pluginManager.register(plugin) }
fun <T : Any?> appData(key: Key<T>, value: T) = appDataManager.register(key, value)
companion object {
@JvmStatic
fun applyUserConfig(cfg: JavalinState, userConfig: Consumer<JavalinConfig>) {
val publicConfig = JavalinConfig(cfg)
addValidationExceptionMapper(cfg) // add default mapper for validation
userConfig.accept(publicConfig) // apply user config through public API wrapper
// Continue with plugin and data manager initialization
cfg.pluginManager.startPlugins()
cfg.appDataManager.registerIfAbsent(ContextResolverKey, cfg.contextResolver)
cfg.appDataManager.registerIfAbsent(AsyncExecutorKey, cfg.concurrency.executor.value)
cfg.appDataManager.registerIfAbsent(ValidationKey, Validation(cfg.validation))
cfg.appDataManager.registerIfAbsent(FileRendererKey, NotImplementedRenderer())
cfg.appDataManager.registerIfAbsent(MaxRequestSizeKey, cfg.http.maxRequestSize)
}
}
//@formatter:on
}
================================================
FILE: javalin/src/main/java/io/javalin/config/JettyConfig.kt
================================================
package io.javalin.config
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
import org.eclipse.jetty.ee10.servlet.SessionHandler
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServletFactory
import org.eclipse.jetty.server.Connector
import org.eclipse.jetty.server.HttpConfiguration
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.util.thread.ThreadPool
import java.util.function.BiFunction
import java.util.function.Consumer
/**
* Configures the embedded Jetty webserver.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.jetty]
*/
class JettyConfig(private val cfg: JavalinState) {
//@formatter:off
@JvmField var host: String? = null
@JvmField var port = 8080
@JvmField var multipartConfig = MultipartConfig()
@JvmField var threadPool: ThreadPool? = null
/** Default HTTP status code when the server had a timeout. */
@JvmField var timeoutStatus = 408
/** Default HTTP status code when the client closes the connection. */
@JvmField var clientAbortStatus = 499
//@formatter:on
/** Configure the jetty [Server]. This is useful if you want to configure Jetty features that are not exposed by Javalin.
* Consider using the other methods in this class before resorting to this one.
* It can be called multiple times, and the supplied consumers will be called in order. */
fun modifyServer(server: Consumer<Server>) {
cfg.jettyInternal.serverConsumers.add(server)
}
/** Configure the jetty [ServletContextHandler]. The [SessionHandler] can be set here.
* It can be called multiple times, and the supplied consumers will be called in order. */
fun modifyServletContextHandler(consumer: Consumer<ServletContextHandler>) {
cfg.jettyInternal.servletContextHandlerConsumers.add(consumer)
}
/** Configure the jetty [JettyWebSocketServletFactory].
* It can be called multiple times, and the supplied consumers will be called in order. */
fun modifyWebSocketServletFactory(wsFactoryConfig: Consumer<JettyWebSocketServletFactory>) {
cfg.jettyInternal.wsFactoryConfigs.add(wsFactoryConfig)
}
/** Configure the [HttpConfiguration] to be used by the jetty [Server].
* It can be called multiple times, and the supplied consumers will be called in order. */
fun modifyHttpConfiguration(httpConfigurationConfig: Consumer<HttpConfiguration>) {
cfg.jettyInternal.httpConfigurationConfigs.add(httpConfigurationConfig)
}
/** Add a [Connector] to the jetty [Server].
* It can be called multiple times, and the supplied connectors will be added in order. */
fun addConnector(connector : BiFunction<Server, HttpConfiguration, Connector>){
cfg.jettyInternal.connectors.add(connector)
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/JettyInternalConfig.kt
================================================
package io.javalin.config
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServletFactory
import org.eclipse.jetty.server.Connector
import org.eclipse.jetty.server.HttpConfiguration
import org.eclipse.jetty.server.Server
import java.util.function.BiFunction
import java.util.function.Consumer
class JettyInternalConfig {
// @formatter:off
@JvmField var server: Server? = null
@JvmField var serverConsumers: MutableList<Consumer<Server>> = mutableListOf()
@JvmField var httpConfigurationConfigs: MutableList<Consumer<HttpConfiguration>> = mutableListOf()
@JvmField var servletContextHandlerConsumers: MutableList<Consumer<ServletContextHandler>> = mutableListOf()
@JvmField var wsFactoryConfigs: MutableList<Consumer<JettyWebSocketServletFactory>> = mutableListOf()
@JvmField var connectors: MutableList<BiFunction<Server, HttpConfiguration, Connector>> = mutableListOf()
// @formatter:on
}
================================================
FILE: javalin/src/main/java/io/javalin/config/MultipartConfig.kt
================================================
package io.javalin.config
import jakarta.servlet.MultipartConfigElement
/**
* This class contains the configuration for handling multipart file uploads
*
* @property cacheDirectory : the directory where files which exceed the maximum in memory size should be cached
* @property maxFileSize : the maximum size allowed (in bytes) for an individual uploaded file
* @property maxTotalRequestSize : the maximum size allowed (in bytes) for the entire multipart request
* @property maxInMemoryFileSize : the maximum size allowed (in bytes) before uploads are cached to disk
*/
class MultipartConfig {
private var cacheDirectory = System.getProperty("java.io.tmpdir")
private var maxFileSize: Long = -1
private var maxTotalRequestSize: Long = -1
private var maxInMemoryFileSize: Int = 1
/**
* Sets the location of the cache directory used to write file uploads
*
* @param path : the path of the cache directory used to write file uploads > maxInMemoryFileSize
*/
fun cacheDirectory(path: String) {
this.cacheDirectory = path
}
/**
* Sets the maximum file size for an individual file upload
*
* @param size : the maximum size of the file
* @param sizeUnit : the units that this size is measured in
*/
fun maxFileSize(size: Long, sizeUnit: SizeUnit) {
this.maxFileSize = size * sizeUnit.multiplier
}
/**
* Sets the maximum size for a single file before it will be cached to disk rather than read in memory
*
* @param size : the maximum size of the file
* @param sizeUnit : the units that this size is measured in
*/
fun maxInMemoryFileSize(size: Int, sizeUnit: SizeUnit) {
this.maxInMemoryFileSize = size * sizeUnit.multiplier
}
/**
* Sets the maximum size for the entire multipart request
*
* @param size : the maximum size of the file
* @param sizeUnit : the units that this size is measured in
*/
fun maxTotalRequestSize(size: Long, sizeUnit: SizeUnit) {
this.maxTotalRequestSize = size * sizeUnit.multiplier
}
/**
* builds a multipart configuration element from the current file upload settings
*/
internal fun multipartConfigElement(): MultipartConfigElement {
return MultipartConfigElement(cacheDirectory, maxFileSize, maxTotalRequestSize, maxInMemoryFileSize)
}
}
/**
* This class represents the potential file size descriptors to avoid the use of hard-coded multipliers
*/
enum class SizeUnit(val multiplier: Int) {
BYTES(1),
KB(1024),
MB(1024 * 1024),
GB(1024 * 1024 * 1024)
}
================================================
FILE: javalin/src/main/java/io/javalin/config/RequestLoggerConfig.kt
================================================
package io.javalin.config
import io.javalin.http.RequestLogger
import io.javalin.websocket.WsConfig
import java.util.function.Consumer
/**
* Configuration for http requests and websocket loggers.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.requestLogger]
*/
class RequestLoggerConfig(private val cfg: JavalinState) {
/** Adds a request logger for HTTP requests. Multiple loggers can be registered and will be invoked in order. */
fun http(requestLogger: RequestLogger) {
cfg.httpRequestLoggers.add(requestLogger)
}
/** Adds a request logger for websocket requests. */
fun ws(ws: Consumer<WsConfig>) {
val logger = WsConfig()
ws.accept(logger)
cfg.wsRequestLogger = logger
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/RouterConfig.kt
================================================
@file:Suppress("internal", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package io.javalin.config
import io.javalin.http.HttpStatus.INTERNAL_SERVER_ERROR
import io.javalin.router.exception.JavaLangErrorHandler
import io.javalin.router.HandlerWrapper
import io.javalin.util.JavalinLogger
/**
* Configuration for the Router.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.router]
*/
class RouterConfig() {
@JvmSynthetic
internal var handlerWrapper: HandlerWrapper? = null
@JvmSynthetic
internal var javaLangErrorHandler: JavaLangErrorHandler = JavaLangErrorHandler { res, error ->
res.status = INTERNAL_SERVER_ERROR.code
JavalinLogger.error("Fatal error occurred while servicing http-request", error)
}
// @formatter:off
/** The context path (ex '/blog' if you are hosting an app on a subpath, like 'mydomain.com/blog') */
@JvmField var contextPath = "/"
/** If true, treat '/path' and '/path/' as the same path (default: true). */
@JvmField var ignoreTrailingSlashes = true
/** If true, treat '/path//subpath' and '/path/subpath' as the same path (default: false). */
@JvmField var treatMultipleSlashesAsSingleSlash = false
/** If true, treat '/PATH' and '/path' as the same path (default: false). */
@JvmField var caseInsensitiveRoutes = false
// @formatter:on
fun handlerWrapper(handlerWrapper: HandlerWrapper) {
this.handlerWrapper = handlerWrapper
}
fun javaLangErrorHandler(handler: JavaLangErrorHandler) {
this.javaLangErrorHandler = handler
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/RoutesConfig.kt
================================================
@file:Suppress("internal", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package io.javalin.config
import io.javalin.apibuilder.ApiBuilder
import io.javalin.apibuilder.EndpointGroup
import io.javalin.http.ExceptionHandler
import io.javalin.http.Handler
import io.javalin.router.Endpoint
import io.javalin.router.JavalinDefaultRoutingApi
import io.javalin.security.RouteRole
import io.javalin.websocket.WsConfig
import io.javalin.websocket.WsExceptionHandler
import io.javalin.websocket.WsHandlerType
import java.util.function.Consumer
/**
* Configuration for Routes - provides direct access to HTTP verbs and routing methods.
* This is the new preferred way to define routes in Javalin 7.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.routes]
*/
class RoutesConfig(internal val cfg: JavalinState) : JavalinDefaultRoutingApi {
override fun <E : Exception> exception(exceptionClass: Class<E>, exceptionHandler: ExceptionHandler<in E>): RoutesConfig = apply {
cfg.internalRouter.addHttpExceptionHandler(exceptionClass, exceptionHandler)
}
override fun error(status: Int, contentType: String, handler: Handler): RoutesConfig = apply {
cfg.internalRouter.addHttpErrorHandler(status, contentType, handler)
}
override fun addEndpoint(endpoint: Endpoint): RoutesConfig = apply {
cfg.internalRouter.addHttpEndpoint(endpoint)
}
override fun <E : Exception> wsException(exceptionClass: Class<E>, exceptionHandler: WsExceptionHandler<in E>): RoutesConfig = apply {
cfg.internalRouter.addWsExceptionHandler(exceptionClass, exceptionHandler)
}
override fun addWsHandler(handlerType: WsHandlerType, path: String, wsConfig: Consumer<WsConfig>, vararg roles: RouteRole): RoutesConfig = apply {
cfg.internalRouter.addWsHandler(handlerType, path, wsConfig, *roles)
}
/**
* Adds routes using the ApiBuilder DSL.
* This method allows you to define routes using the static methods from ApiBuilder.
*
* @param endpoints the endpoint group containing the route definitions
* @return this RoutesConfig instance for method chaining
*/
fun apiBuilder(endpoints: EndpointGroup): RoutesConfig = apply {
try {
ApiBuilder.setStaticJavalin(this)
endpoints.addEndpoints()
} finally {
ApiBuilder.clearStaticJavalin()
}
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/SpaRootConfig.kt
================================================
package io.javalin.config
import io.javalin.http.Handler
import io.javalin.http.SinglePageHandler
import io.javalin.http.staticfiles.Location
/**
* Configures a Single Page Application root.
*
* Single page application (SPA) mode is similar to static file handling.
* It runs after endpoint matching, and after static file handling. It’s
* basically a very fancy 404 mapper, which converts any 404’s into a
* specified page. You can define multiple single page handlers for your
* application by specifying different root paths.
*
* @see [SinglePageHandler]
*/
class SpaRootConfig(private val cfg: JavalinState) {
@JvmOverloads
fun addFile(hostedPath: String, filePath: String, location: Location = Location.CLASSPATH) {
cfg.singlePageHandler.add(hostedPath, filePath, location)
}
fun addHandler(hostedPath: String, customHandler: Handler) {
cfg.singlePageHandler.add(hostedPath, customHandler)
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/StartupConfig.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.config
/**
* Miscellaneous application-level configuration options.
*/
class StartupConfig {
@JvmField var showJavalinBanner = true
@JvmField var showOldJavalinVersionWarning = true
@JvmField var startupWatcherEnabled = true
}
================================================
FILE: javalin/src/main/java/io/javalin/config/StaticFilesConfig.kt
================================================
package io.javalin.config
import io.javalin.http.Header
import io.javalin.http.staticfiles.Location
import io.javalin.http.staticfiles.StaticFileConfig
import io.javalin.jetty.JettyResourceHandler
import io.javalin.security.RouteRole
import java.util.function.Consumer
/**
* Configuration for static files and webjars.
*
* Static resource handling is done after endpoint matching,
* meaning your own GET endpoints have higher priority.
*
* @param cfg the parent Javalin Configuration
* @see [JavalinState.staticFiles]
*/
class StaticFilesConfig(private val cfg: JavalinState) {
/** Enable webjars access. They will be available at /webjars/name/version/file.ext. */
fun enableWebjars() = add { staticFiles ->
staticFiles.hostedPath = "/webjars"
staticFiles.directory = "META-INF/resources/webjars"
staticFiles.headers = mapOf(Header.CACHE_CONTROL to "max-age=31622400")
}
/**
* Adds the given directory as a static file containers.
* @param directory the directory where your files are located
* @param location the location of the static directory (default: CLASSPATH)
* @param roles the roles which can access the the static directory (default: emptySet())
*/
@JvmOverloads
fun add(directory: String, location: Location = Location.CLASSPATH, roles: Set<RouteRole> = emptySet()) = add { staticFiles ->
staticFiles.directory = directory
staticFiles.location = location
staticFiles.roles = roles
}
/**
* Adds a static file through custom configuration.
* @param userConfig a lambda to configure advanced static files
*/
fun add(userConfig: Consumer<StaticFileConfig>) {
if (cfg.resourceHandler == null) {
cfg.resourceHandler = JettyResourceHandler()
}
val finalConfig = StaticFileConfig()
userConfig.accept(finalConfig)
cfg.resourceHandler!!.addStaticFileConfig(finalConfig)
}
}
================================================
FILE: javalin/src/main/java/io/javalin/config/ValidationConfig.kt
================================================
package io.javalin.config
class ValidationConfig() {
internal val converters = mutableMapOf<Class<*>, (String) -> Any?>(
java.lang.Boolean::class.java to { it.toBoolean() },
java.lang.Double::class.java to { it.toDouble() },
java.lang.Float::class.java to { it.toFloat() },
java.lang.Integer::class.java to { it.toInt() },
java.lang.Long::class.java to { it.toLong() },
java.lang.String::class.java to { it },
Boolean::class.java to { it.toBoolean() },
Double::class.java to { it.toDouble() },
Float::class.java to { it.toFloat() },
Int::class.java to { it.toInt() },
Long::class.java to { it.toLong() },
String::class.java to { it }
)
fun register(clazz: Class<*>, converter: (String) -> Any?) {
converters[clazz] = converter
}
}
================================================
FILE: javalin/src/main/java/io/javalin/event/EventManager.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.event
import io.javalin.http.Handler
import io.javalin.http.HandlerType
import io.javalin.security.RouteRole
import io.javalin.websocket.WsConfig
import io.javalin.websocket.WsHandlerType
import java.util.function.Consumer
/**
* Class propagating events from the Jetty webserver to any registered listener.
*/
class EventManager {
val lifecycleHandlers = JavalinLifecycleEvent.entries.associateWith { HashSet<LifecycleEventListener>() }
var handlerAddedHandlers = mutableSetOf<Consumer<HandlerMetaInfo>>()
val wsHandlerAddedHandlers = mutableSetOf<Consumer<WsHandlerMetaInfo>>()
/** Fires a Javalin Lifecycle Event to the listeners. */
fun fireEvent(javalinLifecycleEvent: JavalinLifecycleEvent) = lifecycleHandlers[javalinLifecycleEvent]?.forEach { it.handleEvent() }
/** Fires an event telling listeners that a new HTTP handler has been added.*/
fun fireHandlerAddedEvent(metaInfo: HandlerMetaInfo) = handlerAddedHandlers.onEach { it.accept(metaInfo) }
/** Fires an event telling listeners that a new WebSocket handler has been added. */
fun fireWsHandlerAddedEvent(metaInfo: WsHandlerMetaInfo) = wsHandlerAddedHandlers.onEach { it.accept(metaInfo) }
internal fun addLifecycleEvent(event: JavalinLifecycleEvent, lifecycleEventListener: LifecycleEventListener) {
lifecycleHandlers[event]!!.add(lifecycleEventListener)
}
}
/**
* The possible Javalin lifecycle event
*/
enum class JavalinLifecycleEvent {
/** Event fired when attempting to start the Jetty Webserver */
SERVER_STARTING,
/** Event fired when the Jetty Webserver was started successfully */
SERVER_STARTED,
/** Event fired when an exception occurs while starting the Jetty Webserver */
SERVER_START_FAILED,
/** Event fired when an exception occurs while stopping the Jetty Webserver */
SERVER_STOP_FAILED,
/** Event fired when attempting to stop the Jetty Webserver */
SERVER_STOPPING,
/** Event fired after the Jetty Webserver was stopped successfully */
SERVER_STOPPED
}
/**
* Metadata information about a HTTP Handler.
* @param httpMethod the [HandlerType] method (e.g.: GET, POST, …)
* @param path the path (e.g.: "/home")
* @param handler the actual [Handler]
* @param roles the authorization roles
*/
data class HandlerMetaInfo(
val httpMethod: HandlerType,
val path: String,
val handler: Handler,
val roles: Set<RouteRole>
)
/**
* Metadata information about a WebSocket Handler.
* @param handlerType the [WsHandlerType] method (e.g.: WEBSOCKET_BEFORE, WEBSOCKET, WEBSOCKET_AFTER)
* @param path the path (e.g.: "/home")
* @param wsConfig the actual [WsConfig] consumer
* @param roles the authorization roles
*/
data class WsHandlerMetaInfo(
val handlerType: WsHandlerType,
val path: String,
val wsConfig: Consumer<WsConfig>,
val roles: Set<RouteRole>
)
================================================
FILE: javalin/src/main/java/io/javalin/event/LifecycleEventListener.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.event
/**
* Main interface for Lifecycle Event Handlers.
* A Runnable does not suffice because the event handler may throw a checked exception.
*
* @see <a href="https://javalin.io/documentation#lifecycle-events">Lifecycle Events in documentation</a>
*/
fun interface LifecycleEventListener {
@Throws(Exception::class) fun handleEvent()
}
================================================
FILE: javalin/src/main/java/io/javalin/http/ContentType.kt
================================================
package io.javalin.http
/**
* List of mime types for the most common file types.
*
* Sources:
* * [Mozilla / Common Types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)
* * [Apache / Mime Types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
*/
enum class ContentType(
/** Standardized mime-type */
val mimeType: String,
/**
* Utility property describes if given format is readable as a text
* or visible as media file by common tools, like e.g. browsers
*/
val isHumanReadable: Boolean,
/** Common file extensions for this type */
vararg val extensions: String,
) {
/* Text */
TEXT_PLAIN("text/plain", true, "txt"),
TEXT_CSS("text/css", true, "css"),
TEXT_CSV("text/csv", false, "csv"),
TEXT_HTML("text/html", true, "html", "htm"),
TEXT_JS("text/javascript", true, "js", "mjs"),
TEXT_MARKDOWN("text/markdown", true, "md"),
TEXT_PROPERTIES("text/x-java-properties", true, "properties"),
TEXT_XML("text/xml", true, "xml"),
/* Image */
IMAGE_AVIF("image/avif", true, "avif"),
IMAGE_BMP("image/bmp", true, "bmp"),
IMAGE_GIF("image/gif", true, "gif"),
IMAGE_ICO("image/vnd.microsoft.icon", true, "ico"),
IMAGE_JPEG("image/jpeg", true, "jpeg", "jpg"),
IMAGE_PNG("image/png", true, "png"),
IMAGE_SVG("image/svg+xml", true, "svg"),
IMAGE_TIFF("image/tiff", true, "tiff", "tif"),
IMAGE_WEBP("image/webp", true, "webp"),
/* Audio */
AUDIO_AAC("audio/aac", true, "aac"),
AUDIO_MIDI("audio/midi", true, "mid", "midi"),
AUDIO_MPEG("audio/mpeg", true, "mp3"),
AUDIO_OGA("audio/ogg", true, "oga"),
AUDIO_OPUS("audio/opus", true, "opus"),
AUDIO_WAV("audio/wav", true, "wav"),
AUDIO_WEBA("audio/weba", true, "waba"),
/* Video */
VIDEO_AVI("video/x-msvideo", true, "avi"),
VIDEO_MP4("video/mp4", true, "mp4"),
VIDEO_MPEG("video/mpeg", true, "mpeg"),
VIDEO_OGG("video/ogg", true, "ogg"),
VIDEO_WEBM("video/webm", true, "webm"),
/* Font */
FONT_OTF("font/otf", false, "otf"),
FONT_TTF("font/ttf", false, "ttf"),
FONT_WOFF("font/woff", false, "woff"),
FONT_WOFF2("font/woff2", false, "woff2"),
/* Application */
APPLICATION_OCTET_STREAM("application/octet-stream", false, "bin"),
APPLICATION_BZ("application/x-bzip", false, "bz"),
APPLICATION_BZ2("application/x-bzip2", false, "bz2"),
APPLICATION_BR("application/brotli", false, "br"),
APPLICATION_CDN("application/cdn", true, "cdn"),
APPLICATION_DOC("application/msword", false, "doc"),
APPLICATION_DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document", false, "docx"),
APPLICATION_EPUB("application/epub+zip", false, "epub"),
APPLICATION_GZ("application/gzip", false, "gz"),
APPLICATION_JSON("application/json", true, "json"),
APPLICATION_MPKG("application/vnd.apple.installer+xml", false, "mpkg"),
APPLICATION_JAR("application/java-archive", false, "jar"),
APPLICATION_PDF("application/pdf", true, "pdf"),
APPLICATION_POM("application/xml", true, "pom"),
APPLICATION_RAR("application/vnd.rar", false, "rar"),
APPLICATION_SH("application/x-sh", true, "sh"),
APPLICATION_SWF("application/x-shockwave-flash", false, "swf"),
APPLICATION_TAR("application/x-tar", false, "tar"),
APPLICATION_XHTML("application/xhtml+xml", true, "xhtml"),
APPLICATION_YAML("application/yaml", true, "yaml", "yml"),
APPLICATION_ZIP("application/zip", false, "zip"),
APPLICATION_7Z("application/x-7z-compressed", false, "7z"),
/* Other */
MULTIPART_FORM_DATA("multipart/form-data", false, "multipart/form-data");
override fun toString(): String =
mimeType
companion object {
/* Compile time common constants - useful for annotations & as raw string values */
const val PLAIN = "text/plain"
const val CSS = "text/css"
const val HTML = "text/html"
const val XML = "text/xml"
const val OCTET_STREAM = "application/octet-stream"
const val JAVASCRIPT = "text/javascript"
const val JSON = "application/json"
const val FORM_DATA = "multipart/form-data"
@JvmStatic
fun contentType(mimeType: String): ContentType? =
values().find { it.mimeType.equals(mimeType, ignoreCase = true) }
@JvmStatic
fun contentTypeByExtension(extension: String): ContentType? =
values().firstOrNull { type ->
type.extensions.any {
extension.equals(it, ignoreCase = true)
}
}
@JvmStatic
fun mimeTypeByExtension(extensions: String): String? =
contentTypeByExtension(extensions)?.mimeType
}
}
================================================
FILE: javalin/src/main/java/io/javalin/http/Context.kt
================================================
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.http
import io.javalin.config.ContextResolverConfig.Companion.ContextResolverKey
import io.javalin.config.Key
import io.javalin.http.ContentType.APPLICATION_JSON
import io.javalin.http.servlet.MaxRequestSize
import io.javalin.http.servlet.attributeOrCompute
import io.javalin.http.servlet.cacheAndSetSessionAttribute
import io.javalin.http.servlet.cachedSessionAttributeOrCompute
import io.javalin.http.servlet.getBasicAuthCredentials
import io.javalin.http.servlet.getCachedRequestAttributeOrSessionAttribute
import io.javalin.http.servlet.getRequestCharset
import io.javalin.http.servlet.readAndResetStreamIfPossible
import io.javalin.http.servlet.splitKeyValueStringAndGroupByKey
import io.javalin.http.util.AsyncExecutor.Companion.AsyncExecutorKey
import io.javalin.http.util.AsyncTaskConfig
import io.javalin.http.util.CookieStore
import io.javalin.http.util.MultipartUtil
import io.javalin.http.util.SeekableWriter
import io.javalin.json.JsonMapper
import io.javalin.plugin.ContextPlugin
import io.javalin.rendering.FileRenderer.Companion.FileRendererKey
import io.javalin.router.Endpoint
import io.javalin.router.Endpoints
import io.javalin.security.BasicAuthCredentials
import io.javalin.security.RouteRole
import io.javalin.util.function.ThrowingRunnable
import io.javalin.validation.BodyValidator
import io.javalin.validation.Validation.Companion.ValidationKey
import io.javalin.validation.Validator
import jakarta.servlet.ServletOutputStream
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import java.io.InputStream
import java.lang.reflect.Type
import java.nio.charset.Charset
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
import java.util.function.Supplier
import java.util.stream.Stream
import kotlin.reflect.KClass
import kotlin.reflect.javaType
import kotlin.reflect.typeOf
/**
* Provides access to functions for handling the request and response
*
* @see <a href="https://javalin.io/documentation#context">Context in docs</a>
*/
// don't suppress warnings, since annotated classes are ignored by dokka (yeah...)
interface Context {
/** Servlet request */
fun req(): HttpServletRequest
/** Servlet response */
fun res(): HttpServletResponse
/** Gets all endpoints visited during this request (in order) */
fun endpoints(): Endpoints
/** Gets the matched Endpoint */
fun endpoint(): Endpoint
///////////////////////////////////////////////////////////////
// Config-ish methods
///////////////////////////////////////////////////////////////
/** Get app data by key */
fun <T> appData(key: Key<T>): T
/** Get configured [JsonMapper] */
fun jsonMapper(): JsonMapper
///////////////////////////////////////////////////////////////
// Plugin-related methods
///////////////////////////////////////////////////////////////
/** Fetch the context extension for a plugin */
fun <T> with(clazz: Class<out ContextPlugin<*, T>>): T
fun <T> with(clazz: KClass<out ContextPlugin<*, T>>): T = with(clazz.java)
///////////////////////////////////////////////////////////////
// Request-ish methods
///////////////////////////////////////////////////////////////
/** Gets the request content length. */
fun contentLength(): Int = req().contentLength
/** Gets the request content type, or null. */
fun contentType(): String? = req().contentType
/** Gets the request method. */
fun method(): HandlerType = HandlerType.findOrCreate(header(Header.X_HTTP_METHOD_OVERRIDE) ?: req().method)
/** Gets the request path. */
fun path(): String = req().requestURI
/** Gets the request port. */
fun port(): Int = req().serverPort
/** Gets the request protocol. */
fun protocol(): String = req().protocol
/** Gets the request context path. */
fun contextPath(): String = req().contextPath
/** Gets the request user agent, or null. */
fun userAgent(): String? = req().getHeader(Header.USER_AGENT)
/** Try to obtain request encoding from [Header.CONTENT_TYPE] header */
fun characterEncoding(): String? = getRequestCharset(this)
/** Gets the request url. */
fun url(): String = appData(ContextResolverKey).url.invoke(this)
/** Gets the full request url, including query string (if present) */
fun fullUrl(): String = appData(ContextResolverKey).fullUrl.invoke(this)
/** Gets the request scheme. */
fun scheme(): String = appData(ContextResolverKey).scheme.invoke(this)
/** Gets the request host, or null. */
fun host(): String? = appData(ContextResolverKey).host.invoke(this)
/** Gets the request ip. */
fun ip(): String = appData(ContextResolverKey).ip.invoke(this)
/** Gets the request body as a [String]. */
fun body(): String = bodyAsBytes().toString(Charset.forName(characterEncoding() ?: "UTF-8"))
/**
* Gets the request body as a [ByteArray].
* Calling this method returns the body as a [ByteArray]. If [io.javalin.config.HttpConfig.maxRequestSize]
* is set and body is bigger than its value, a [io.javalin.http.HttpResponseException] is throw,
* with status 413 CONTENT_TOO_LARGE.
*/
fun bodyAsBytes(): ByteArray {
val maxRequestSize = appData(MaxRequestSize.MaxRequestSizeKey)
return MaxRequestSize.readBytesWithLimit(req().inputStream, maxRequestSize)
}
/** Maps a JSON body to a Java/Kotlin class using the registered [io.javalin.json.JsonMapper] */
fun <T> bodyAsClass(type: Type): T = when {
isJson() || !strictContentTypes() -> jsonMapper().fromJsonString(body(), type)
else -> throw BadRequestResponse("Content-Type is not application/json")
}
/** Maps a JSON body to a Java/Kotlin class using the registered [io.javalin.json.JsonMapper] */
fun <T> bodyAsClass(clazz: Class<T>): T = bodyAsClass(type = clazz as Type)
/** Maps a JSON body to a Java/Kotlin class using the registered [io.javalin.json.JsonMapper] */
fun <T> bodyStreamAsClass(type: Type): T = when {
isJson() || !strictContentTypes() -> jsonMapper().fromJsonStream(req().inputStream, type)
else -> throw BadRequestResponse("Content-Type is not application/json")
}
/** Gets the underlying [InputStream] for the request body */
fun bodyInputStream(): InputStream = req().inputStream
/** Creates a typed [BodyValidator] for the body() value */
fun <T> bodyValidator(clazz: Class<T>): BodyValidator<T?> = BodyValidator(body(), clazz) { bodyAsClass(clazz) }
/** Gets a form param if it exists, else null */
fun formParam(key: String): String? = formParams(key).firstOrNull()
/** Creates a typed [Validator] for the formParam() value */
fun <T> formParamAsClass(key: String, clazz: Class<T>) = appData(ValidationKey).validator(key, clazz, formParam(key))
/** Gets a list of form params for the specified key, or empty list. */
fun formParams(key: String): List<String> = formParamMap()[key] ?: emptyList()
/** Gets a list of form params for the specified key, or empty list. */
fun <T : Any> formParamsAsClass(key: String, clazz: Class<T>): Validator<List<T>?> {
val params = (formParamMap()[key] ?: emptyList()).map {
appData(ValidationKey).validator(key, clazz, it).required().get()
}
return appData(ValidationKey).validator(key, params)
}
/** Gets a map with all the form param keys and values. */
fun formParamMap(): Map<String, List<String>> = when {
isMultipartFormData() -> MultipartUtil.fieldMap(req(), multipartConfig())
isFormUrlencoded() || !strictContentTypes() -> splitKeyValueStringAndGroupByKey(body(), characterEncoding() ?: "UTF-8")
else -> mapOf()
}
/** Gets the multipart configuration for this context */
fun multipartConfig(): io.javalin.config.MultipartConfig
fun strictContentTypes(): Boolean
/**
* Gets a path param by name (ex: pathParam("param").
*
* Ex: If the handler path is /users/{user-id},
* and a browser GETs /users/123,
* pathParam("user-id") will return "123"
*/
fun pathParam(key: String): String
/** Creates a typed [Validator] for the pathParam() value */
fun <T> pathParamAsClass(key: String, clazz: Class<T>) = appData(ValidationKey).validator(key, clazz, pathParam(key))
/** Gets a map of all the [pathParamAsClass] keys and values. */
fun pathParamMap(): Map<String, String>
/** Gets a query param if it exists, else null */
fun queryParam(key: String): String? = queryParams(key).firstOrNull()
/** Creates a typed [Validator] for the queryParam() value */
fun <T> queryParamAsClass(key: String, clazz: Class<T>) = appData(ValidationKey).validator(key, clazz, queryParam(key))
/** Gets a list of query params for the specified key, or empty list. */
fun queryParams(key: String): List<String> = queryParamMap()[key] ?: emptyList()
/** Gets a list of query params for the specified key, or empty list. */
fun <T : Any> queryParamsAsClass(key: String, clazz: Class<T>): Validator<List<T>?> {
val params = (queryParamMap()[key] ?: emptyList()).map {
appData(ValidationKey).validator(key, clazz, it).required().get()
}
return appData(ValidationKey).validator(key, params)
}
/** Gets a map with all the query param keys and values. */
fun queryParamMap(): Map<String, List<String>> = splitKeyValueStringAndGroupByKey(queryString() ?: "", characterEncoding() ?: "UTF-8")
/** Gets the request query string, or null. */
fun queryString(): String? = req().queryString
/** Sets an attribute for the user session. */
fun sessionAttribute(key: String, value: Any?) = req().session.setAttribute(key, value)
/** Gets specified attribute from the user session, or null. */
@Suppress("UNCHECKED_CAST")
fun <T> sessionAttribute(key: String): T? = req().getSession(false)?.getAttribute(key) as? T
/** Get session attribute, and set value to null */
fun <T> consumeSessionAttribute(key: String): T? = sessionAttribute<T?>(key).also { this.sessionAttribute(key, null) }
/** Sets an attribute for the user session, and caches it on the request */
fun cachedSessionAttribute(key: String, value: Any?) = cacheAndSetSessionAttribute(key, value, req())
/** Gets specified attribute from the request attribute cache, or the user session, or null. */
fun <T> cachedSessionAttribute(key: String): T? = getCachedRequestAttributeOrSessionAttribute(key, req())
/** Gets specified attribute from the request attribute cache, or the user session, or computes the value from callback. */
fun <T> cachedSessionAttributeOrCompute(key: String, callback: (Context) -> T): T? = cachedSessionAttributeOrCompute(callback, key, this)
/** Gets a map of all the attributes in the user session. */
fun sessionAttributeMap(): Map<String, Any?> = req().session.attributeNames.asSequence().associateWith { sessionAttribute(it) }
/** Sets an attribute on the request(). Attributes are available to other handlers in the request lifecycle */
fun attribute(key: String, value: Any?) = req().setAttribute(key, value)
/** Gets the specified attribute from the request(). */
@Suppress("UNCHECKED_CAST")
fun <T> attribute(key: String): T? = req().getAttribute(key) as? T
/** Gets specified [attribute], or computes the value from callback (and sets the attribute) */
fun <T> attributeOrCompute(key: String, callback: (Context) -> T): T? = attributeOrCompute(callback, key, this)
/** Gets a map with all the attribute keys and values on the request(). */
fun attributeMap(): Map<String, Any?> = req().attributeNames.asSequence().associateWith { attribute(it) as Any? }
/** Gets cookie store used by this request */
fun cookieStore(): CookieStore = CookieStore(this)
/** Gets a request cookie by name, or null. */
fun cookie(name: String): String? = req().cookies?.find { it.name == name }?.value
/** Gets a map with all the cookie keys and values on the request(). */
fun cookieMap(): Map<String, String> = req().cookies?.associate { it.name to it.value } ?: emptyMap()
/** Gets a request header by name, or null. */
fun header(header: String): String? = req().getHeader(header)
/** Creates a typed [Validator] for the header() value */
fun <T> headerAsClass(header: String, clazz: Class<T>) = appData(ValidationKey).validator(header, clazz, header(header))
/** Gets a map with all the header keys and values on the request(). */
fun headerMap(): Map<String, String> = req().headerNames.asSequence().associateWith { header(it)!! }
/**
* Gets basic-auth credentials from the request, or throws.
*
* Returns a wrapper object [BasicAuthCredentials] which contains the
* Base64 decoded username and password from the Authorization header,
* or null if basic-auth is not properly configured
*/
fun basicAuthCredentials(): BasicAuthCredentials? = getBasicAuthCredentials(header(Header.AUTHORIZATION))
/** Returns true if request is multipart. */
fun isMultipart(): Boolean = header(Header.CONTENT_TYPE)?.startsWith("multipart/", ignoreCase = true) == true
/** Returns true if request is multipart/form-data. */
fun isMultipartFormData(): Boolean = header(Header.CONTENT_TYPE)?.startsWith("multipart/form-data", ignoreCase = true) == true
/** Returns true if request is application/x-www-form-urlencoded. */
fun isFormUrlencoded(): Boolean = header(Header.CONTENT_TYPE)?.startsWith("application/x-www-form-urlencoded", ignoreCase = true) == true
/** Returns true if request is application/json. */
fun isJson(): Boolean = header(Header.CONTENT_TYPE)?.startsWith("application/json", ignoreCase = true) == true
/** Gets first [UploadedFile] for the specified name, or null. */
fun uploadedFile(fileName: String): UploadedFile? = uploadedFiles(fileName).firstOrNull()
/** Gets a list of [UploadedFile]s for the specified name, or empty list. */
fun uploadedFiles(fileName: String): List<UploadedFile> = when {
isMultipartFormData() -> MultipartUtil.uploadedFiles(req(), fileName, multipartConfig())
else -> listOf()
}
/** Gets a list of [UploadedFile]s, or empty list. */
fun uploadedFiles(): List<UploadedFile> = when {
isMultipartFormData() -> MultipartUtil.uploadedFiles(req(), multipartConfig())
else -> listOf()
}
/**
* Gets a map of all uploaded files as a map where the key is the name of the parameter the file was uploaded as and
* the value is the list of files uploaded under that parameter.
*
* If called on a non-multipart request this returns an empty map
*/
fun uploadedFileMap(): Map<String, List<UploadedFile>> = when {
isMultipartFormData() -> MultipartUtil.uploadedFileMap(req(), multipartConfig())
else -> emptyMap()
}
///////////////////////////////////////////////////////////////
// Response-ish methods
///////////////////////////////////////////////////////////////
/** Gets the current response [Charset]. */
fun responseCharset(): Charset = try { Charset.forName(res().characterEncoding) } catch (_: Exception) { Charset.defaultCharset() }
/**
* Gets the output stream you can write to.
* This stream by default uses compression specified in the Javalin configuration.
* If you're looking for the servlet's raw, uncompressed output stream, use `ctx.res().outputStream`.
* @see [HttpServletResponse.getOutputStream]
*/
fun outputStream(): ServletOutputStream
/**
* The output stream returned by outputStream() will use compression (as specified in Javalin configuration), but
* compression will happen only if the first write to the output stream is larger than `minSizeForCompression`.
* Calling this function with a value of zero will cause compression to always be used.
* The default value is set to the value of [io.javalin.compression.CompressionStrategy.defaultMinSizeForCompression].
* This function must be called before calling [outputStream] for the first time.
*/
fun minSizeForCompression(minSizeForCompression: Int): Context
/**
* Disables compression for the response output stream.
* Equivalent to calling [minSizeForCompression] with [Integer.MAX_VALUE].
*/
fun disableCompression(): Context = minSizeForCompression(Int.MAX_VALUE)
/**
* Writes the specified inputStream as a seekable stream.
* You can change this default in [io.javalin.config.JavalinState].
*
* @return the [CompletableFuture] used to write the seekable stream
*/
fun writeSeekableStream(inputStream: InputStream, contentType: String, totalBytes: Long) = SeekableWriter.write(this, inputStream, contentType, totalBytes)
/**
* Writes input stream to [writeSeekableStream] with currently available data ([InputStream.available])
* @see writeSeekableStream]
*/
fun writeSeekableStream(inputStream: InputStream, contentType: String) = writeSeekableStream(inputStream, contentType, inputStream.available().toLong())
/**
* Sets context result to the specified [String].
* Will overwrite the current result if there is one.
*/
fun result(resultString: String): Context = result(resultString.byteInputStream(responseCharset()))
/**
* Sets context result to the specified array of bytes.
* Will overwrite the current result if there is one.
*/
fun result(resultBytes: ByteArray): Context = result(resultBytes.inputStream())
/**
* Sets context result to the specified [InputStream].
* Will overwrite the current result if there is one.
*/
fun result(resultStream: InputStream): Context
/** Gets the current [io.javalin.http.servlet.JavalinServletContext.resultInputStream] as a [String] (if set), and reset the underlying stream */
fun result(): String? = readAndResetStreamIfPossible(resultInputStream(), responseCharset())
/** Gets the underlying [InputStream] for the result ([io.javalin.http.servlet.JavalinServletContext.resultInputStream]) */
fun resultInputStream(): InputStream?
/**
* Utility function that allows to run async task on top of the [Context.future] method.
* It means you should treat provided task as a result of this handler, and you can't use any other result function simultaneously.
*
* @param config Configuration of the async task with properties like executor, timeout, etc.
* @param task The task that will be executed asynchronously.
*
* @return As a result, function returns a new future that you can listen to.
* The limitation is that you can't modify context after such event,
* because it'll most likely be executed when the connection is already closed,
* so it's just not thread-safe.
*/
fun async(config: Consumer<AsyncTaskConfig>, task: ThrowingRunnable<Exception>) =
appData(AsyncExecutorKey).submitAsyncTask(this, AsyncTaskConfig().also { config.accept(it) }, task)
/* @see [async] */
fun async(task: ThrowingRunnable<Exception>) = async(config = {}, task = task)
/**
* The main entrypoint for all async related functionalities exposed by [Context].
*
* @param future Future represents any delayed in time result.
* Upon this value Javalin will schedule further execution of this request().
* When servlet will detect that the given future is completed, request will be executed synchronously,
* otherwise request will be executed asynchronously by a thread which will complete the future.
* @throws IllegalStateException if result was already set
*/
fun future(future: Supplier<out CompletableFuture<*>>)
/** Sets response content type to specified [String] value. */
fun contentType(contentType: String): Context = also { res().contentType = contentType }
/** Sets response content type to specified [ContentType] value. */
fun contentType(contentType: ContentType): Context = contentType(contentType.mimeType)
/** Sets response header by name and value. */
fun header(name: String, value: String): Context = also { res().setHeader(name, value) }
/** Remove header by name. */
fun removeHeader(name: String): Context = also { res().setHeader(name, null) }
/** Redirects to location with given status. Skips HTTP handler if called in before/beforeMatched handler */
fun redirect(location: String, status: HttpStatus)
/** Redirects to location with status [HttpStatus.FOUND]. Skips HTTP handler if called in before/beforeMatched handler */
fun redirect(location: String) = redirect(location, HttpStatus.FOUND)
/** Sets the response status. */
fun status(status: HttpStatus): Context = also { res().status = status.code }
/** Sets the response status. */
fun status(status: Int): Context = also { res().status = status }
/** Gets the response status. For non-standard codes, [HttpStatus.UNKNOWN] is returned, the specific code can be obtained using [statusCode] */
fun status(): HttpStatus = HttpStatus.forStatus(res().status)
/** Gets the response status code */
fun statusCode(): Int = res().status
/** Sets a cookie with name, value, and max-age = -1. */
fun cookie(name: String, value: String): Context = cookie(name, value, -1)
/** Sets a cookie with name, value and max-age property*/
fun cookie(name: String, value: String, maxAge: Int): Context = cookie(Cookie(name = name, value = value, maxAge = maxAge))
/** Sets a Cookie. */
fun cookie(cookie: Cookie): Context = also { res().setJavalinCookie(cookie) }
/** Removes cookie specified by name and path (optional). */
fun removeCookie(name: String, path: String?): Context = also { res().removeCookie(name, path) }
/** Removes cookie specified by name */
fun removeCookie(name: String): Context = removeCookie(name, "/")
/**
* Serializes object to a JSON-string using the registered [io.javalin.json.JsonMapper] and sets it as the context result.
* Also sets content type to application/json.
*/
fun json(obj: Any, type: Type): Context = contentType(APPLICATION_JSON).result(jsonMapper().toJsonString(obj, type))
/** @see [json] */
fun json(obj: Any): Context = json(obj, obj::class.java)
/**
* Serializes object to a JSON-stream using the registered [io.javalin.json.JsonMapper] and sets it as the context result.
* Also sets content type to application/json.
*/
fun jsonStream(obj: Any, type: Type): Context = contentType(APPLICATION_JSON).result(jsonMapper().toJsonStream(obj, type))
/** @see [jsonStream] */
fun jsonStream(obj: Any): Context = jsonStream(obj, obj::class.java)
/**
* Consumes the specified stream with the configured JsonMapper, which transforms the stream's
* content to JSON, writing the results directly to the response's `outputStream` as the stream
* is consumed. This function call is synchronous, and may be wrapped in `ctx.async { }` if needed.
* The response will always be compressed regardless of size, given that compression is enabled in
* the Javalin configuration.
*/
fun writeJsonStream(stream: Stream<*>)
/** Sets context result to specified html string and sets content-type to text/html. */
fun html(html: String): Context = contentType(ContentType.TEXT_HTML).result(html)
/**
* Renders a file with specified values and sets it as the context result.
* Also sets content-type to text/html.
* Determines the correct rendering-function based on the file extension.
*/
fun render(filePath: String, model: Map<String, Any?>): Context = html(appData(FileRendererKey).render(filePath, model, this))
/** @see render() */
fun render(filePath: String): Context = render(filePath, mutableMapOf())
///////////////////////////////////////////////////////////////
// Other methods
///////////////////////////////////////////////////////////////
fun skipRemainingHandlers(): Context
fun routeRoles(): Set<RouteRole>
}
/** Reified version of [Context.json] (Kotlin only) */
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Any> Context.jsonAsType(obj: T): Context = json(obj, typeOf<T>().javaType)
/** Reified version of [Context.bodyAsClass] (Kotlin only) */
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Any> Context.bodyAsClass(): T = bodyAsClass(typeOf<T>().javaType)
/** Reified version of [Context.bodyStreamAsClass] (Kotlin only) */
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Any> Context.bodyStreamAsClass(): T = bodyStreamAsClass(typeOf<T>().javaType)
/** Reified version of [Context.bodyValidator] (Kotlin only) */
inline fun <reified T : Any> Context.bodyValidator(): BodyValidator<T?> = bodyValidator(T::class.java)
/** Reified version of [Context.pathParamAsClass] (Kotlin only) */
inline fun <reified T : Any> Context.pathParamAsClass(key: String): Validator<T?> = pathParamAsClass(key, T::class.java)
/** Reified version of [Context.headerAsClass] (Kotlin only) */
inline fun <reified T : Any> Context.headerAsClass(header: String): Validator<T?> = headerAsClass(header, T::class.java)
/** Reified version of [Context.queryParamAsClass] (Kotlin only) */
inline fun <reified T : Any> Context.queryParamAsClass(key: String): Validator<T?> = queryParamAsClass(key, T::class.java)
/** Reified version of [Context.queryParamsAsClass] (Kotlin only) */
inline fun <reified T : Any> Context.queryParamsAsClass(key: String): Validator<List<T>?> = queryParamsAsClass(key, T::class.java)
/** Reified version of [Context.formParamAsClass] (Kotlin only) */
inline fun <reified T : Any> Context.formParamAsClass(key: String): Validator<T?> = formParamAsClass(key, T::class.java)
/** Reified version of [Context.formParamsAsClass] (Kotlin only) */
inline fun <reified T : Any> Context.formParamsAsClass(key: String): Validator<List<T>?> = formParamsAsClass(key, T::class.java)
================================================
FILE: javalin/src/main/java/io/javalin/http/Cookie.kt
================================================
package io.javalin.http
import jakarta.servlet.http.HttpServletResponse
import jakarta.servlet.http.Cookie as ServletCookie
const val SAME_SITE = "SameSite"
/**
* Value to define the `SameSite` property of a cookie.
*/
enum class SameSite(val value: String) {
/** Means that the browser sends the cookie with both cross-site and same-site requests.*/
NONE("$SAME_SITE=None"),
/**
* Means that the browser sends the cookie only for same-site requests,
* that is, requests originating from the same site that set the cookie.
* If a request originates from a different domain or scheme (even with
* the same domain), no cookies with the SameSite=Strict attribute are sent.
*/
STRICT("$SAME_SITE=Strict"),
/**
* Means that the cookie is not sent on cross-site requests, such as on
* requests to load images or frames, but is sent when a user is na
gitextract_bkbr0xf4/ ├── .editorconfig ├── .github/ │ ├── README.md │ ├── copilot-instructions.md │ ├── dependabot.yml │ └── workflows/ │ ├── cleanup-performance-preview.yml │ ├── main.yml │ ├── publish-snapshots.yml │ └── test-performance-command.yml ├── .gitignore ├── .mvn/ │ └── wrapper/ │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── jacoco-coverage-report/ │ ├── README.md │ └── pom.xml ├── javalin/ │ ├── module-info.java │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── io/ │ │ └── javalin/ │ │ ├── Javalin.java │ │ ├── apibuilder/ │ │ │ ├── ApiBuilder.java │ │ │ ├── CrudHandler.kt │ │ │ └── EndpointGroup.java │ │ ├── compression/ │ │ │ ├── Brotli.kt │ │ │ ├── Brotli4jCompressor.kt │ │ │ ├── CompressedStream.kt │ │ │ ├── CompressionStrategy.kt │ │ │ ├── CompressionType.kt │ │ │ ├── Compressor.kt │ │ │ ├── Gzip.kt │ │ │ ├── GzipCompressor.kt │ │ │ ├── Zstd.kt │ │ │ └── ZstdCompressor.kt │ │ ├── config/ │ │ │ ├── AppDataManager.kt │ │ │ ├── BundledPluginsConfig.kt │ │ │ ├── ConcurrencyConfig.kt │ │ │ ├── ContextResolverConfig.kt │ │ │ ├── EventConfig.kt │ │ │ ├── HttpConfig.kt │ │ │ ├── JavalinConfig.kt │ │ │ ├── JavalinState.kt │ │ │ ├── JettyConfig.kt │ │ │ ├── JettyInternalConfig.kt │ │ │ ├── MultipartConfig.kt │ │ │ ├── RequestLoggerConfig.kt │ │ │ ├── RouterConfig.kt │ │ │ ├── RoutesConfig.kt │ │ │ ├── SpaRootConfig.kt │ │ │ ├── StartupConfig.kt │ │ │ ├── StaticFilesConfig.kt │ │ │ └── ValidationConfig.kt │ │ ├── event/ │ │ │ ├── EventManager.kt │ │ │ └── LifecycleEventListener.kt │ │ ├── http/ │ │ │ ├── ContentType.kt │ │ │ ├── Context.kt │ │ │ ├── Cookie.kt │ │ │ ├── ExceptionHandler.java │ │ │ ├── Handler.java │ │ │ ├── HandlerType.java │ │ │ ├── Header.kt │ │ │ ├── HttpResponseException.kt │ │ │ ├── HttpStatus.kt │ │ │ ├── RequestLogger.java │ │ │ ├── SinglePageHandler.kt │ │ │ ├── UploadedFile.kt │ │ │ ├── servlet/ │ │ │ │ ├── DefaultTasks.kt │ │ │ │ ├── JavalinServlet.kt │ │ │ │ ├── JavalinServletContext.kt │ │ │ │ ├── JavalinServletRequest.kt │ │ │ │ ├── JavalinWsServletContext.kt │ │ │ │ ├── MaxRequestSize.kt │ │ │ │ ├── ServletEntry.kt │ │ │ │ └── Task.kt │ │ │ ├── sse/ │ │ │ │ ├── Emitter.kt │ │ │ │ ├── SseClient.kt │ │ │ │ └── SseHandler.kt │ │ │ ├── staticfiles/ │ │ │ │ ├── JavalinStaticResourceHandler.kt │ │ │ │ ├── ResourceHandler.java │ │ │ │ ├── StaticFileConfig.kt │ │ │ │ ├── StaticFileHandler.kt │ │ │ │ └── StaticResource.kt │ │ │ └── util/ │ │ │ ├── AsyncUtil.kt │ │ │ ├── CookieStore.kt │ │ │ ├── ETagGenerator.kt │ │ │ ├── JsonEscapeUtil.kt │ │ │ ├── MethodNotAllowedUtil.kt │ │ │ ├── MultipartUtil.kt │ │ │ └── SeekableWriter.kt │ │ ├── jetty/ │ │ │ ├── JavalinJettyServlet.kt │ │ │ ├── JettyPrecompressingResourceHandler.kt │ │ │ ├── JettyResourceHandler.kt │ │ │ ├── JettyServer.kt │ │ │ └── JettyUtil.kt │ │ ├── json/ │ │ │ ├── JavalinGson.kt │ │ │ ├── JavalinJackson.kt │ │ │ ├── JsonMapper.kt │ │ │ └── PipedStreamUtil.kt │ │ ├── plugin/ │ │ │ ├── PluginApi.kt │ │ │ ├── PluginExceptions.kt │ │ │ ├── PluginManager.kt │ │ │ └── bundled/ │ │ │ ├── BasicAuthPlugin.kt │ │ │ ├── CorsPlugin.kt │ │ │ ├── CorsUtils.kt │ │ │ ├── DevLoggerPlugin.kt │ │ │ ├── GlobalHeadersPlugin.kt │ │ │ ├── HttpAllowedMethodsPlugin.kt │ │ │ ├── JavalinVuePlugin.kt │ │ │ ├── RateLimitPlugin.kt │ │ │ ├── RedirectToLowercasePathPlugin.kt │ │ │ ├── RouteOverviewPlugin.kt │ │ │ ├── RouteOverviewUtil.kt │ │ │ └── SslRedirectPlugin.kt │ │ ├── rendering/ │ │ │ └── FileRenderer.kt │ │ ├── router/ │ │ │ ├── Endpoint.kt │ │ │ ├── Endpoints.kt │ │ │ ├── HandlerWrapper.kt │ │ │ ├── InternalRouter.kt │ │ │ ├── JavalinDefaultRoutingApi.kt │ │ │ ├── ParsedEndpoint.kt │ │ │ ├── error/ │ │ │ │ └── ErrorMapper.kt │ │ │ ├── exception/ │ │ │ │ ├── ExceptionMapper.kt │ │ │ │ ├── HttpResponseExceptionMapper.kt │ │ │ │ └── JavaLangErrorHandler.kt │ │ │ └── matcher/ │ │ │ ├── ParserExceptions.kt │ │ │ ├── ParserState.kt │ │ │ ├── PathMatcher.kt │ │ │ ├── PathParser.kt │ │ │ ├── PathSegment.kt │ │ │ └── RoutingRegexes.kt │ │ ├── security/ │ │ │ ├── BasicAuthCredentials.kt │ │ │ └── RouteRole.kt │ │ ├── util/ │ │ │ ├── ConcurrencyUtil.kt │ │ │ ├── FileUtil.kt │ │ │ ├── JavalinExceptions.kt │ │ │ ├── JavalinLogger.kt │ │ │ ├── OptionalDependency.kt │ │ │ ├── ReflectionUtil.kt │ │ │ ├── Util.kt │ │ │ ├── function/ │ │ │ │ ├── ThrowingConsumer.java │ │ │ │ └── ThrowingRunnable.java │ │ │ └── legacy/ │ │ │ └── LegacyAccessManager.kt │ │ ├── validation/ │ │ │ ├── BodyValidator.kt │ │ │ ├── Validation.kt │ │ │ └── Validator.kt │ │ ├── vue/ │ │ │ ├── JavalinVueConfig.kt │ │ │ ├── LoadableData.kt │ │ │ ├── VueComponent.kt │ │ │ ├── VueDependencyResolver.java │ │ │ ├── VueFileInliner.kt │ │ │ ├── VueHandler.kt │ │ │ ├── VuePathMaster.kt │ │ │ ├── VueRenderer.kt │ │ │ └── VueStateRenderer.kt │ │ └── websocket/ │ │ ├── WsAutomaticPing.kt │ │ ├── WsCloseStatus.kt │ │ ├── WsConfig.java │ │ ├── WsConnection.kt │ │ ├── WsContext.kt │ │ ├── WsExceptionHandler.java │ │ ├── WsExceptionMapper.kt │ │ ├── WsHandlers.kt │ │ ├── WsPathMatcher.kt │ │ ├── WsRouter.kt │ │ └── WsUpgradeLogger.java │ └── test/ │ ├── external/ │ │ ├── html.html │ │ └── txt.txt │ ├── java/ │ │ └── io/ │ │ └── javalin/ │ │ ├── LargeSeekableInput.kt │ │ ├── TestApiBuilder.kt │ │ ├── TestApiBuilderWebSocket.java │ │ ├── TestAppData.kt │ │ ├── TestBeforeAfterMatched.kt │ │ ├── TestBeforeMatched.kt │ │ ├── TestBodyReading.kt │ │ ├── TestClose.kt │ │ ├── TestClose_Java.java │ │ ├── TestCompression.kt │ │ ├── TestConcurrencyUtil.kt │ │ ├── TestConfiguration.kt │ │ ├── TestConfigureServletContextHandler.kt │ │ ├── TestContextHandlerType.java │ │ ├── TestContextPath.kt │ │ ├── TestContextRouteRoles.kt │ │ ├── TestCookie.kt │ │ ├── TestCookieStore.kt │ │ ├── TestCors.kt │ │ ├── TestCorsUtils.kt │ │ ├── TestCustomJetty.kt │ │ ├── TestCustomJettyHttpConfiguration.kt │ │ ├── TestCustomRequestLifecycle.kt │ │ ├── TestDependencyUtil.kt │ │ ├── TestEncoding.kt │ │ ├── TestEndpoint.kt │ │ ├── TestErrorMapper.kt │ │ ├── TestEtags.kt │ │ ├── TestEventManager.kt │ │ ├── TestExceptionMapper.kt │ │ ├── TestFilters.kt │ │ ├── TestFuture.kt │ │ ├── TestGlobalGlobalHeaderConfigPlugin.kt │ │ ├── TestGracefulShutdown.java │ │ ├── TestHandlerWrapper.kt │ │ ├── TestHttpAllowedMethodsPlugin.kt │ │ ├── TestHttpResponseExceptions.kt │ │ ├── TestJavalinGson.kt │ │ ├── TestJavalinInstanceAndConfigApi.kt │ │ ├── TestJavalinInstanceAndConfigApi_Java.java │ │ ├── TestJavalinJackson.kt │ │ ├── TestJson.kt │ │ ├── TestJsonMapper.kt │ │ ├── TestJsonMapperExtensions.kt │ │ ├── TestLegacyAccessManager.kt │ │ ├── TestLifecycleEvents.kt │ │ ├── TestLogging.kt │ │ ├── TestMaxRequestSize.kt │ │ ├── TestMethodNotAllowed.kt │ │ ├── TestMocking.kt │ │ ├── TestMultipartForms.kt │ │ ├── TestMultipleSlashes.kt │ │ ├── TestPlugins.kt │ │ ├── TestPublicApi_Java.java │ │ ├── TestRedirectToLowercasePathPlugin.kt │ │ ├── TestRendering.kt │ │ ├── TestRequest.kt │ │ ├── TestRequest_Java.java │ │ ├── TestResponse.kt │ │ ├── TestRoutesConfig.kt │ │ ├── TestRouting.kt │ │ ├── TestServerHeader.kt │ │ ├── TestSse.kt │ │ ├── TestSslRedirectPlugin.kt │ │ ├── TestTrailingSlashes.kt │ │ ├── TestUnixSocketConnector.kt │ │ ├── TestUnsafeStateAccess.kt │ │ ├── TestUtil.kt │ │ ├── TestValidation.kt │ │ ├── TestValidation_Java.java │ │ ├── TestWebBrowser.kt │ │ ├── examples/ │ │ │ ├── CopilotInstructionsPatternValidation.java │ │ │ ├── FileUploadExample.java │ │ │ ├── HelloWorld.java │ │ │ ├── HelloWorldApi.java │ │ │ ├── HelloWorldAsync.java │ │ │ ├── HelloWorldAuth.java │ │ │ ├── HelloWorldBasicAuth.java │ │ │ ├── HelloWorldCors.java │ │ │ ├── HelloWorldCustomJsonMapper.java │ │ │ ├── HelloWorldFuture.java │ │ │ ├── HelloWorldPlugin.java │ │ │ ├── HelloWorldSecure.java │ │ │ ├── HelloWorldServlet.java │ │ │ ├── HelloWorldSse.java │ │ │ ├── HelloWorldStaticFiles.java │ │ │ ├── HelloWorldStaticFiles_external.java │ │ │ ├── HelloWorldStaticFiles_linked.java │ │ │ └── HelloWorldWebSockets.java │ │ ├── http/ │ │ │ ├── ContentTypeTest.kt │ │ │ ├── HttpResponseExceptionTest.kt │ │ │ ├── HttpStatusCodeTest.kt │ │ │ └── TestCustomHttpMethods.kt │ │ ├── javalinvue/ │ │ │ ├── TestJavalinVue.kt │ │ │ ├── TestJavalinVueBrowser.kt │ │ │ ├── TestJavalinVueHandler.java │ │ │ ├── TestJavalinVueResolution.java │ │ │ └── VueTestUtil.kt │ │ ├── performance/ │ │ │ ├── PathMatcherBenchmark.java │ │ │ ├── PerformanceBenchmarkSuite.java │ │ │ └── SimpleAsyncTest.java │ │ ├── routeoverview/ │ │ │ ├── TestRouteOverviewInJava.java │ │ │ ├── TestRouteOverviewInKotlin.kt │ │ │ ├── TestRouteOverviewPlugin.kt │ │ │ └── VisualTest.java │ │ ├── staticfiles/ │ │ │ ├── StaticFilesTestUtil.kt │ │ │ ├── TestSinglePageMode.kt │ │ │ ├── TestStaticDirectorySlash.kt │ │ │ ├── TestStaticFileAccess.kt │ │ │ ├── TestStaticFiles.kt │ │ │ ├── TestStaticFilesEdgeCases.kt │ │ │ ├── TestStaticFilesPathTraversal.kt │ │ │ └── TestStaticFilesPrecompressor.kt │ │ ├── testing/ │ │ │ ├── FasterJacksonMapper.kt │ │ │ ├── HttpUtil.kt │ │ │ ├── JavalinTestUtil.java │ │ │ ├── NonSerializableObject.java │ │ │ ├── RunResult.java │ │ │ ├── SerializableObject.java │ │ │ ├── TestDependency.kt │ │ │ ├── TestEnvironment.kt │ │ │ ├── TestServlet.java │ │ │ ├── TestUtil.java │ │ │ ├── ThrowingBiConsumer.java │ │ │ ├── TypedException.java │ │ │ ├── UploadInfo.kt │ │ │ └── WebDriverUtil.kt │ │ └── websocket/ │ │ ├── TestWebSocket.kt │ │ ├── TestWebSocketHttp2.kt │ │ ├── TestWsBeforeAfter.kt │ │ ├── TestWsContext.kt │ │ ├── TestWsException.kt │ │ ├── TestWsLogging.kt │ │ ├── TestWsRouting.kt │ │ ├── TestWsUpgrade.kt │ │ └── WebSocketTestHelpers.kt │ ├── kotlin/ │ │ └── io/ │ │ └── javalin/ │ │ ├── TestRateLimitPlugin.kt │ │ └── examples/ │ │ ├── AdvancedServerSentEvent.kt │ │ ├── FileUploadExample.kt │ │ ├── HelloWorld.kt │ │ ├── HelloWorldApi.kt │ │ ├── HelloWorldAsync.kt │ │ ├── HelloWorldAuth.kt │ │ ├── HelloWorldCors.kt │ │ ├── HelloWorldCustomJsonMapper.kt │ │ ├── HelloWorldImages.kt │ │ ├── HelloWorldPlugin.kt │ │ ├── HelloWorldSecure.kt │ │ ├── HelloWorldSse.kt │ │ ├── HelloWorldStaticFiles.kt │ │ ├── HelloWorldStaticFiles_external.kt │ │ ├── HelloWorldWebSockets.kt │ │ └── KotlinExample.kt │ └── resources/ │ ├── keystore.jks │ ├── markdown/ │ │ └── test.md │ ├── public/ │ │ ├── assets/ │ │ │ └── filtered-styles.css │ │ ├── file │ │ ├── file.javalin │ │ ├── html.html │ │ ├── module.mjs │ │ ├── protected/ │ │ │ └── secret.html │ │ ├── readme.md.br │ │ ├── script.js │ │ ├── sse/ │ │ │ └── sse-example.html │ │ ├── styles.css │ │ ├── subdir/ │ │ │ └── index.html │ │ └── subpage/ │ │ └── index.html │ ├── public2/ │ │ └── secret.txt │ ├── upload-test/ │ │ └── text.txt │ └── vue/ │ ├── dependency-1-foo.vue │ ├── dependency-1.vue │ ├── dependency-123.vue │ ├── dependency-one-3.vue │ ├── dependency-one.vue │ ├── dependency-two-3.vue │ ├── dependency-two.vue │ ├── layout.html │ ├── multi-dependency.vue │ ├── nested-dependency.vue │ ├── scripts-dev.js │ ├── scripts-not-dev.js │ ├── scripts.js │ ├── test-component-3.vue │ ├── test-component.vue │ ├── view-multiline-dependency.vue │ ├── view-nested-dependency.vue │ ├── view-number-dependency.vue │ ├── view-one-3.vue │ ├── view-one.vue │ ├── view-three.vue │ └── view-two.vue ├── javalin-bom/ │ └── pom.xml ├── javalin-bundle/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── resources/ │ └── logback.xml ├── javalin-micrometer/ │ ├── README.md │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── kotlin/ │ │ │ └── io/ │ │ │ └── javalin/ │ │ │ └── micrometer/ │ │ │ └── MicrometerPlugin.kt │ │ └── module-info.java │ └── test/ │ └── kotlin/ │ └── io/ │ └── javalin/ │ └── micrometer/ │ └── MicrometerPluginTest.kt ├── javalin-ssl/ │ ├── README.md │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── kotlin/ │ │ │ └── io/ │ │ │ └── javalin/ │ │ │ └── community/ │ │ │ └── ssl/ │ │ │ ├── SslConfig.kt │ │ │ ├── SslConfigException.kt │ │ │ ├── SslPlugin.kt │ │ │ ├── TlsConfig.kt │ │ │ ├── TrustConfig.kt │ │ │ └── util/ │ │ │ ├── ConnectorFactory.kt │ │ │ └── SSLUtils.kt │ │ └── module-info.java │ └── test/ │ ├── java/ │ │ └── io/ │ │ └── javalin/ │ │ └── community/ │ │ └── ssl/ │ │ └── JavaAPITests.java │ ├── kotlin/ │ │ └── io/ │ │ └── javalin/ │ │ └── community/ │ │ └── ssl/ │ │ ├── APITests.kt │ │ ├── IntegrationTestClass.kt │ │ ├── KeystoreLoadingTests.kt │ │ ├── PemLoadingTests.kt │ │ ├── SslConfigExceptionTest.kt │ │ ├── SslConfigTests.kt │ │ ├── SslPluginTest.kt │ │ ├── TlsConfigTest.kt │ │ ├── TrustConfigTests.kt │ │ └── certs/ │ │ ├── CertificateAuthorityTests.kt │ │ ├── Client.kt │ │ └── Server.kt │ └── resources/ │ ├── ca/ │ │ ├── client-fullchain.cer │ │ ├── client-nochain.cer │ │ ├── client.key │ │ ├── keystores/ │ │ │ ├── client.p12 │ │ │ ├── issuer-ca.p12 │ │ │ ├── root-ca.p12 │ │ │ └── server.p12 │ │ ├── root-ca.cer │ │ ├── server.cer │ │ └── server.key │ ├── client/ │ │ ├── cert.der │ │ ├── cert.jks │ │ ├── cert.p12 │ │ ├── cert.p7b │ │ ├── cert.pem │ │ └── key.pem │ └── server/ │ ├── cert.crt │ ├── encrypted.key │ ├── keystore.jks │ ├── keystore.p12 │ ├── malformed.jks │ ├── malformed.p12 │ ├── norway.jks │ ├── norway.p12 │ ├── passwordless.key │ └── wrong.pem ├── javalin-testtools/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── io/ │ │ └── javalin/ │ │ └── testtools/ │ │ ├── HttpClient.kt │ │ ├── JavalinTest.kt │ │ ├── TestCase.java │ │ └── TestTool.kt │ └── test/ │ ├── java/ │ │ └── io/ │ │ └── javalin/ │ │ └── testtools/ │ │ ├── JavaApp.java │ │ ├── JavaTest.java │ │ └── TestCookieIssue.java │ └── kotlin/ │ └── io/ │ └── javalin/ │ └── testtools/ │ ├── KotlinApp.kt │ ├── KotlinTest.kt │ └── TestCookieIssue.kt ├── javalin-utils/ │ ├── javalin-context-mock/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ └── java/ │ │ │ └── io/ │ │ │ └── javalin/ │ │ │ └── mock/ │ │ │ ├── Body.kt │ │ │ ├── ContextMock.kt │ │ │ ├── ContextMockConfig.kt │ │ │ ├── ContextMockConfigurer.kt │ │ │ └── servlet/ │ │ │ ├── InMemoryHttpServletRequest.kt │ │ │ ├── InMemoryHttpServletResponse.kt │ │ │ ├── InMemoryHttpSession.kt │ │ │ └── InMemoryPart.kt │ │ └── test/ │ │ └── java/ │ │ └── io/ │ │ └── javalin/ │ │ └── mock/ │ │ └── TestMockContext.kt │ ├── javalin-rendering/ │ │ ├── javalin-rendering-commonmark/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── markdown/ │ │ │ │ └── Commonmark.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestCommonmark.kt │ │ │ └── resources/ │ │ │ └── markdown/ │ │ │ └── test.md │ │ ├── javalin-rendering-freemarker/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ ├── JavalinFreemarker.kt │ │ │ │ └── TemplateUtil.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestFreemarker.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ ├── freemarker/ │ │ │ │ ├── test-with-base.ftl │ │ │ │ └── test.ftl │ │ │ ├── test-with-base.ftl │ │ │ └── test.ftl │ │ ├── javalin-rendering-handlebars/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ └── JavalinHandlebars.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestHandlebars.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ └── handlebars/ │ │ │ └── test.hbs │ │ ├── javalin-rendering-jte/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ └── JavalinJte.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestJte.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ └── jte/ │ │ │ ├── test-variable.jte │ │ │ └── test.jte │ │ ├── javalin-rendering-mustache/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ ├── JavalinMustache.kt │ │ │ │ └── TemplateUtil.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestMustache.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ ├── mustache/ │ │ │ │ └── test.mustache │ │ │ └── test.mustache │ │ ├── javalin-rendering-pebble/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ ├── JavalinPebble.kt │ │ │ │ └── TemplateUtil.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestPebble.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ ├── pebble/ │ │ │ │ ├── test-empty-context-map.peb │ │ │ │ └── test.peb │ │ │ ├── test-empty-context-map.peb │ │ │ └── test.peb │ │ ├── javalin-rendering-thymeleaf/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ ├── JavalinThymeleaf.kt │ │ │ │ └── TemplateUtil.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestThymeleaf.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ ├── test.html │ │ │ ├── testUrls.html │ │ │ └── thymeleaf/ │ │ │ ├── test.html │ │ │ └── testUrls.html │ │ ├── javalin-rendering-velocity/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── rendering/ │ │ │ │ └── template/ │ │ │ │ ├── JavalinVelocity.kt │ │ │ │ └── TemplateUtil.kt │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── io/ │ │ │ │ └── javalin/ │ │ │ │ └── TestVelocity.kt │ │ │ └── resources/ │ │ │ └── templates/ │ │ │ ├── test-set.vm │ │ │ ├── test.vm │ │ │ └── velocity/ │ │ │ ├── test-set.vm │ │ │ └── test.vm │ │ └── pom.xml │ ├── pom.properties │ └── pom.xml ├── mvnw ├── mvnw.cmd ├── pom.properties └── pom.xml
SYMBOL INDEX (357 symbols across 61 files)
FILE: javalin-ssl/src/test/java/io/javalin/community/ssl/JavaAPITests.java
class JavaAPITests (line 7) | public class JavaAPITests {
method javaApiCompiles (line 9) | static void javaApiCompiles(){
FILE: javalin-testtools/src/main/java/io/javalin/testtools/TestCase.java
type TestCase (line 5) | @FunctionalInterface
method accept (line 7) | void accept(Javalin server, HttpClient client) throws Exception;
FILE: javalin-testtools/src/test/java/io/javalin/testtools/JavaApp.java
class JavaApp (line 10) | public class JavaApp {
class HelloController (line 19) | static class HelloController {
method hello (line 20) | public static void hello(Context ctx) {
FILE: javalin-testtools/src/test/java/io/javalin/testtools/JavaTest.java
class JavaTest (line 21) | public class JavaTest {
class MyJavaClass (line 23) | static class MyJavaClass {
method MyJavaClass (line 27) | public MyJavaClass() {
method MyJavaClass (line 30) | public MyJavaClass(String field1, String field2) {
method get_method_works (line 36) | @Test
method can_do_query_params_and_headers (line 47) | @Test
method post_with_json_serialization_works (line 60) | @Test
method all_common_verbs_work (line 70) | @Test
method request_method_works (line 87) | @Test
method custom_javalin_works (line 99) | @Test
method capture_std_out_works (line 109) | @Test
method testing_full_app_works (line 124) | @Test
method custom_httpClient_is_used (line 132) | @Test
method instantiate_JavalinTestTool (line 152) | @Test
method exceptions_in_test_code_get_rethrown (line 161) | public void exceptions_in_test_code_get_rethrown() {
method exceptions_in_handler_code_are_caught_by_exception_handler_and_not_thrown (line 169) | @Test
method exception_in_handler_code_is_included_in_test_logs (line 182) | @Test
method response_headers_are_accessible (line 199) | @Test
method empty_and_null_response_bodies_work (line 215) | @Test
method request_builder_with_multiple_headers_works (line 226) | @Test
method different_http_methods_with_custom_bodies_work (line 242) | @Test
FILE: javalin-testtools/src/test/java/io/javalin/testtools/TestCookieIssue.java
class TestCookieIssue (line 9) | public class TestCookieIssue {
method canSetAndReadSessionAttributes (line 11) | @Test
method cookieHandlingWorksAutomatically (line 22) | @Test
FILE: javalin/src/main/java/io/javalin/Javalin.java
class Javalin (line 21) | public class Javalin {
method Javalin (line 26) | protected Javalin(JavalinState state) {
method jettyServer (line 39) | public JettyServer jettyServer() {
method create (line 50) | public static Javalin create() {
method create (line 64) | public static Javalin create(Consumer<JavalinConfig> config) {
method start (line 78) | public static Javalin start(Consumer<JavalinConfig> config) {
method javalinServlet (line 83) | public Servlet javalinServlet() {
method start (line 97) | public Javalin start(String host, int port) {
method start (line 113) | public Javalin start(int port) {
method start (line 128) | public Javalin start() {
method stop (line 138) | public Javalin stop() {
method port (line 150) | public int port() {
FILE: javalin/src/main/java/io/javalin/apibuilder/ApiBuilder.java
class ApiBuilder (line 25) | public class ApiBuilder {
method setStaticJavalin (line 38) | public static void setStaticJavalin(@NotNull JavalinDefaultRoutingApi ...
method clearStaticJavalin (line 47) | public static void clearStaticJavalin() {
method path (line 56) | public static void path(@NotNull String path, @NotNull EndpointGroup e...
method prefixPath (line 63) | public static String prefixPath(@NotNull String path) {
method staticInstance (line 70) | public static JavalinDefaultRoutingApi staticInstance() {
method get (line 88) | public static void get(@NotNull String path, @NotNull Handler handler) {
method get (line 98) | public static void get(@NotNull String path, @NotNull Handler handler,...
method get (line 108) | public static void get(@NotNull Handler handler) {
method get (line 118) | public static void get(@NotNull Handler handler, @NotNull RouteRole......
method post (line 128) | public static void post(@NotNull String path, @NotNull Handler handler) {
method post (line 138) | public static void post(@NotNull String path, @NotNull Handler handler...
method post (line 148) | public static void post(@NotNull Handler handler) {
method query (line 158) | public static void query(@NotNull String path, @NotNull Handler handle...
method query (line 168) | public static void query(@NotNull String path, @NotNull Handler handle...
method query (line 178) | public static void query(@NotNull Handler handler) {
method query (line 188) | public static void query(@NotNull Handler handler, @NotNull RouteRole....
method post (line 198) | public static void post(@NotNull Handler handler, @NotNull RouteRole.....
method put (line 208) | public static void put(@NotNull String path, @NotNull Handler handler) {
method put (line 218) | public static void put(@NotNull String path, @NotNull Handler handler,...
method put (line 228) | public static void put(@NotNull Handler handler) {
method put (line 238) | public static void put(@NotNull Handler handler, @NotNull RouteRole......
method patch (line 248) | public static void patch(@NotNull String path, @NotNull Handler handle...
method patch (line 258) | public static void patch(@NotNull String path, @NotNull Handler handle...
method patch (line 268) | public static void patch(@NotNull Handler handler) {
method patch (line 278) | public static void patch(@NotNull Handler handler, @NotNull RouteRole....
method delete (line 288) | public static void delete(@NotNull String path, @NotNull Handler handl...
method delete (line 298) | public static void delete(@NotNull String path, @NotNull Handler handl...
method delete (line 308) | public static void delete(@NotNull Handler handler) {
method delete (line 318) | public static void delete(@NotNull Handler handler, @NotNull RouteRole...
method head (line 328) | public static void head(@NotNull String path, @NotNull Handler handler) {
method head (line 338) | public static void head(@NotNull String path, @NotNull Handler handler...
method head (line 348) | public static void head(@NotNull Handler handler) {
method head (line 358) | public static void head(@NotNull Handler handler, @NotNull RouteRole.....
method before (line 372) | public static void before(@NotNull String path, @NotNull Handler handl...
method before (line 382) | public static void before(@NotNull Handler handler) {
method beforeMatched (line 392) | public static void beforeMatched(@NotNull String path, @NotNull Handle...
method beforeMatched (line 402) | public static void beforeMatched(@NotNull Handler handler) {
method after (line 412) | public static void after(@NotNull String path, @NotNull Handler handle...
method after (line 422) | public static void after(@NotNull Handler handler) {
method afterMatched (line 432) | public static void afterMatched(@NotNull String path, @NotNull Handler...
method afterMatched (line 442) | public static void afterMatched(@NotNull Handler handler) {
method ws (line 456) | public static void ws(@NotNull String path, @NotNull Consumer<WsConfig...
method ws (line 466) | public static void ws(@NotNull String path, @NotNull Consumer<WsConfig...
method ws (line 476) | public static void ws(@NotNull Consumer<WsConfig> ws) {
method ws (line 486) | public static void ws(@NotNull Consumer<WsConfig> ws, @NotNull RouteRo...
method wsBefore (line 494) | public static void wsBefore(@NotNull String path, @NotNull Consumer<Ws...
method wsBefore (line 502) | public static void wsBefore(@NotNull Consumer<WsConfig> wsConfig) {
method wsAfter (line 510) | public static void wsAfter(@NotNull String path, @NotNull Consumer<WsC...
method wsAfter (line 518) | public static void wsAfter(@NotNull Consumer<WsConfig> wsConfig) {
method sse (line 526) | public static void sse(@NotNull String path, @NotNull Consumer<SseClie...
method sse (line 530) | public static void sse(@NotNull String path, @NotNull Consumer<SseClie...
method sse (line 534) | public static void sse(@NotNull Consumer<SseClient> client) {
method sse (line 538) | public static void sse(@NotNull Consumer<SseClient> client, @NotNull R...
method crud (line 552) | public static void crud(@NotNull CrudHandler crudHandler) {
method crud (line 562) | public static void crud(@NotNull CrudHandler crudHandler, @NotNull Rou...
method crud (line 572) | public static void crud(@NotNull String path, @NotNull CrudHandler cru...
method crud (line 582) | public static void crud(@NotNull String path, @NotNull CrudHandler cru...
FILE: javalin/src/main/java/io/javalin/apibuilder/EndpointGroup.java
type EndpointGroup (line 9) | @FunctionalInterface
method addEndpoints (line 11) | void addEndpoints();
FILE: javalin/src/main/java/io/javalin/http/ExceptionHandler.java
type ExceptionHandler (line 19) | @FunctionalInterface
method handle (line 27) | void handle(@NotNull T exception, @NotNull Context ctx);
FILE: javalin/src/main/java/io/javalin/http/Handler.java
type Handler (line 18) | @FunctionalInterface
method handle (line 28) | void handle(@NotNull Context ctx) throws Exception;
FILE: javalin/src/main/java/io/javalin/http/HandlerType.java
method HandlerType (line 21) | public HandlerType(String name) {
method toString (line 25) | @Override
method findOrCreate (line 69) | public static HandlerType findOrCreate(String name) {
method values (line 86) | public static List<HandlerType> values() {
method commonHttp (line 94) | public static List<HandlerType> commonHttp() {
FILE: javalin/src/main/java/io/javalin/http/RequestLogger.java
type RequestLogger (line 17) | @FunctionalInterface
method handle (line 26) | void handle(@NotNull Context ctx, @NotNull Float executionTimeMs) thro...
FILE: javalin/src/main/java/io/javalin/http/staticfiles/ResourceHandler.java
type ResourceHandler (line 9) | public interface ResourceHandler {
method init (line 14) | default void init(CompressionStrategy compressionStrategy) {}
method canHandle (line 16) | boolean canHandle(Context context);
method handle (line 18) | boolean handle(Context context);
method addStaticFileConfig (line 20) | boolean addStaticFileConfig(StaticFileConfig config);
method resourceRouteRoles (line 22) | Set<RouteRole> resourceRouteRoles(Context ctx);
FILE: javalin/src/main/java/io/javalin/util/function/ThrowingConsumer.java
type ThrowingConsumer (line 4) | @FunctionalInterface
method accept (line 6) | void accept(T t) throws E;
FILE: javalin/src/main/java/io/javalin/util/function/ThrowingRunnable.java
type ThrowingRunnable (line 4) | @FunctionalInterface
method run (line 6) | void run() throws E;
FILE: javalin/src/main/java/io/javalin/vue/VueDependencyResolver.java
class VueDependencyResolver (line 29) | public class VueDependencyResolver {
method VueDependencyResolver (line 37) | public VueDependencyResolver(final Set<Path> paths, String appVarName) {
method resolve (line 58) | public String resolve(final String componentId) {
method resolveTransitiveDependencies (line 85) | private Set<String> resolveTransitiveDependencies(final String compone...
method resolveDirectDependencies (line 103) | private Set<String> resolveDirectDependencies(final String componentId) {
FILE: javalin/src/main/java/io/javalin/websocket/WsConfig.java
class WsConfig (line 14) | public class WsConfig {
method onConnect (line 27) | public void onConnect(@NotNull WsConnectHandler wsConnectHandler) {
method onMessage (line 36) | public void onMessage(@NotNull WsMessageHandler wsMessageHandler) {
method onBinaryMessage (line 45) | public void onBinaryMessage(@NotNull WsBinaryMessageHandler wsBinaryMe...
method onClose (line 56) | public void onClose(@NotNull WsCloseHandler wsCloseHandler) {
method onError (line 64) | public void onError(@NotNull WsErrorHandler wsErrorHandler) {
method onUpgrade (line 73) | public void onUpgrade(@NotNull WsUpgradeLogger wsUpgradeLogger) {
FILE: javalin/src/main/java/io/javalin/websocket/WsExceptionHandler.java
type WsExceptionHandler (line 17) | @FunctionalInterface
method handle (line 19) | void handle(@NotNull T exception, @NotNull WsContext ctx);
FILE: javalin/src/main/java/io/javalin/websocket/WsUpgradeLogger.java
type WsUpgradeLogger (line 18) | @FunctionalInterface
method handle (line 27) | void handle(@NotNull Context ctx, @NotNull Float executionTimeMs) thro...
FILE: javalin/src/test/java/io/javalin/TestApiBuilderWebSocket.java
class TestApiBuilderWebSocket (line 17) | public class TestApiBuilderWebSocket {
method testWsBeforeAndAfterInApiBuilder (line 19) | @Test
FILE: javalin/src/test/java/io/javalin/TestClose_Java.java
class TestClose_Java (line 18) | class TestClose_Java {
method tryWithResourcesStopsServer (line 20) | @Test
method tryWithResourcesCallsLifecycleEvents (line 35) | @Test
method closingInsideTryWithResourcesIsIdempotent (line 53) | @Test
FILE: javalin/src/test/java/io/javalin/TestContextHandlerType.java
class TestContextHandlerType (line 21) | public class TestContextHandlerType {
method testHandlerTypeCanBeAccessedInContext (line 23) | @Test
FILE: javalin/src/test/java/io/javalin/TestGracefulShutdown.java
class TestGracefulShutdown (line 29) | @Disabled("For running manually")
method t1_shutdown_is_graceful_with_default_config (line 36) | @Test
method t2_shutdown_is_graceful_when_custom_server_has_statisticshandler (line 43) | @Test
method t3_shutdown_is_not_graceful_when_custom_server_has_no_statisticshandler (line 54) | @Test
method testIfShutdownIsGraceful (line 63) | private void testIfShutdownIsGraceful(Javalin app) throws Exception {
method addEndpoints (line 70) | private void addEndpoints(Javalin app) {
method performBlockingRequest (line 75) | private void performBlockingRequest(Javalin app) throws Exception {
method performAsyncRequest (line 80) | private Future<HttpResponse<String>> performAsyncRequest(Javalin app) ...
FILE: javalin/src/test/java/io/javalin/TestJavalinInstanceAndConfigApi_Java.java
class TestJavalinInstanceAndConfigApi_Java (line 24) | public class TestJavalinInstanceAndConfigApi_Java {
method testJavalinInstanceAndConfigApi (line 26) | public void testJavalinInstanceAndConfigApi() {
FILE: javalin/src/test/java/io/javalin/TestPublicApi_Java.java
class TestPublicApi_Java (line 28) | public class TestPublicApi_Java {
class TestContextPlugin (line 29) | static public class TestContextPlugin extends ContextPlugin<Void, Hand...
method createExtension (line 30) | public HandlerType createExtension(Context context) {
method main (line 35) | public static void main(String[] args) {
class UserController (line 226) | static class UserController {
method getAll (line 227) | public static void getAll(Context ctx) { /* ... */ }
method create (line 228) | public static void create(Context ctx) { /* ... */ }
method getOne (line 229) | public static void getOne(Context ctx) { /* ... */ }
method update (line 230) | public static void update(Context ctx) { /* ... */ }
method delete (line 231) | public static void delete(Context ctx) { /* ... */ }
method webSocketEvents (line 232) | public static void webSocketEvents(WsConfig wsConfig) { /* ... */ }
class MyObject (line 235) | private static class MyObject {
class User (line 239) | private static class User { }
FILE: javalin/src/test/java/io/javalin/TestRequest_Java.java
class TestRequest_Java (line 9) | public class TestRequest_Java {
method session_attribute_can_be_consumed_easily (line 11) | @Test
FILE: javalin/src/test/java/io/javalin/TestValidation_Java.java
class TestValidation_Java (line 20) | public class TestValidation_Java {
class CustomException (line 21) | private static class CustomException extends RuntimeException {
method CustomException (line 22) | public CustomException(String message) {
method validation_on_context_works_from_java (line 27) | @Test
method default_values_work_from_java (line 35) | @Test
method get_or_throw_works_from_java (line 44) | @Test
method validator_works_from_java_too (line 57) | @Test
FILE: javalin/src/test/java/io/javalin/examples/CopilotInstructionsPatternValidation.java
class CopilotInstructionsPatternValidation (line 18) | public class CopilotInstructionsPatternValidation {
method validateConsumerConfiguration (line 23) | public static void validateConsumerConfiguration() {
method validateNestedConfiguration (line 34) | public static void validateNestedConfiguration() {
method validateHandlerPatterns (line 50) | public static void validateHandlerPatterns() {
method handleData (line 65) | private static void handleData(Context ctx) {
method validateDirectRouting (line 72) | public static void validateDirectRouting() {
method validateApiBuilderRouting (line 84) | public static void validateApiBuilderRouting() {
method validateLifecycleHandlers (line 102) | public static void validateLifecycleHandlers() {
method validateExceptionHandling (line 125) | public static void validateExceptionHandling() {
method validateErrorHandlers (line 140) | public static void validateErrorHandlers() {
method validateContextPatterns (line 155) | public static void validateContextPatterns() {
class TestPlugin (line 181) | static class TestPlugin extends Plugin<TestPlugin.Config> {
method TestPlugin (line 183) | TestPlugin(Consumer<Config> userConfig) {
method onStart (line 187) | @Override
class Config (line 196) | public static class Config {
method validatePluginUsage (line 205) | public static void validatePluginUsage() {
method validateWebSocketPatterns (line 217) | public static void validateWebSocketPatterns() {
method validateAsyncPatterns (line 243) | public static void validateAsyncPatterns() {
method validateVirtualThreads (line 261) | public static void validateVirtualThreads() {
method validateJsonPatterns (line 270) | public static void validateJsonPatterns() {
method main (line 284) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/FileUploadExample.java
class FileUploadExample (line 15) | public class FileUploadExample {
method main (line 17) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorld.java
class HelloWorld (line 12) | public class HelloWorld {
method main (line 13) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldApi.java
class HelloWorldApi (line 16) | public class HelloWorldApi {
method main (line 18) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldAsync.java
class HelloWorldAsync (line 11) | public class HelloWorldAsync {
method main (line 13) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldAuth.java
class HelloWorldAuth (line 23) | public class HelloWorldAuth {
type JRole (line 25) | enum JRole implements RouteRole {
method main (line 29) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldBasicAuth.java
class HelloWorldBasicAuth (line 13) | public class HelloWorldBasicAuth {
method main (line 15) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldCors.java
class HelloWorldCors (line 15) | public class HelloWorldCors {
method main (line 17) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldCustomJsonMapper.java
class HelloWorldCustomJsonMapper (line 16) | public class HelloWorldCustomJsonMapper {
method main (line 18) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldFuture.java
class HelloWorldFuture (line 16) | public class HelloWorldFuture {
method main (line 18) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldPlugin.java
class HelloWorldPlugin (line 15) | public class HelloWorldPlugin {
method main (line 16) | public static void main(String[] args) {
class JRate (line 31) | class JRate extends ContextPlugin<JRate.Config, JRate.Extension> {
method JRate (line 32) | public JRate(Consumer<Config> userConfig) {
method createExtension (line 36) | @Override
class Config (line 40) | public static class Config {
class Extension (line 43) | public class Extension {
method Extension (line 45) | public Extension(Context context) {
method tryConsume (line 48) | public void tryConsume(int cost) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldSecure.java
class HelloWorldSecure (line 14) | public class HelloWorldSecure {
method main (line 18) | public static void main(String[] args) {
method getSslContextFactory (line 35) | private static SslContextFactory.Server getSslContextFactory() {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldServlet.java
class HelloWorldServlet (line 16) | public class HelloWorldServlet {
method main (line 18) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldSse.java
class HelloWorldSse (line 17) | public class HelloWorldSse {
method main (line 19) | public static void main(String[] args) throws InterruptedException {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldStaticFiles.java
class HelloWorldStaticFiles (line 13) | public class HelloWorldStaticFiles {
method main (line 15) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldStaticFiles_external.java
class HelloWorldStaticFiles_external (line 12) | public class HelloWorldStaticFiles_external {
method main (line 14) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldStaticFiles_linked.java
class HelloWorldStaticFiles_linked (line 17) | public class HelloWorldStaticFiles_linked {
method main (line 19) | public static void main(String[] args) {
method createSymLink (line 31) | private static void createSymLink(String targetPath, String linkPath) {
FILE: javalin/src/test/java/io/javalin/examples/HelloWorldWebSockets.java
class HelloWorldWebSockets (line 16) | public class HelloWorldWebSockets {
method main (line 17) | public static void main(String[] args) {
FILE: javalin/src/test/java/io/javalin/javalinvue/TestJavalinVueHandler.java
class TestJavalinVueHandler (line 13) | public class TestJavalinVueHandler {
method testDefaultPreAndPostRenderer (line 15) | @Test
method testPreRenderer (line 27) | @Test
method testPostRenderer (line 44) | @Test
method testVueRenderer (line 61) | @Test
FILE: javalin/src/test/java/io/javalin/javalinvue/TestJavalinVueResolution.java
class TestJavalinVueResolution (line 27) | public class TestJavalinVueResolution {
method resoleAllDependenciesTest (line 29) | @Test
method resolveSingleDependencyTest (line 50) | @Test
method resolveVue3DependencyTest (line 67) | @Test
method resolveNestedDependencyTest (line 96) | @Test
method resolveMultiComponentFileDependencyTest (line 113) | @Test
method componentWithNumberTest (line 142) | @Test
method componentWithMultilineComponentsUsageTest (line 157) | @Test
FILE: javalin/src/test/java/io/javalin/performance/PathMatcherBenchmark.java
class PathMatcherBenchmark (line 20) | @State(Scope.Benchmark)
method main (line 27) | public static void main(String[] args) throws Exception {
method setup (line 37) | @Setup
method matchFirstStream (line 48) | @Benchmark
method matchLastStream (line 53) | @Benchmark
method matchFirstList (line 58) | @Benchmark
method matchLastList (line 63) | @Benchmark
class OldPathMatcher (line 70) | final class OldPathMatcher {
method add (line 76) | public void add(ParsedEndpoint entry) {
method findEntries (line 80) | public List<ParsedEndpoint> findEntries(HandlerType handlerType, Strin...
method match (line 90) | private boolean match(ParsedEndpoint entry, String requestPath) {
FILE: javalin/src/test/java/io/javalin/performance/PerformanceBenchmarkSuite.java
class PerformanceBenchmarkSuite (line 29) | @State(Scope.Benchmark)
method setup (line 52) | @Setup(Level.Trial)
method tearDown (line 93) | @TearDown(Level.Trial)
method plainGet (line 100) | @Benchmark
method singlePathParam (line 105) | @Benchmark
method multiPathParam (line 110) | @Benchmark
method staticFile (line 115) | @Benchmark
method staticFile_miss (line 120) | @Benchmark
method manyRoutes_first (line 125) | @Benchmark
method manyRoutes_last (line 130) | @Benchmark
method postBody (line 135) | @Benchmark
method get (line 142) | private static HttpRequest get(String url) {
method main (line 148) | public static void main(String[] args) throws Exception {
method printTable (line 158) | private static void printTable(Collection<RunResult> results) {
method fmt (line 196) | private static String fmt(double v) {
FILE: javalin/src/test/java/io/javalin/performance/SimpleAsyncTest.java
class SimpleAsyncTest (line 23) | public class SimpleAsyncTest {
method test_async (line 27) | @Test
method timeCallable (line 55) | private void timeCallable(String name, Callable<?> callable) throws Ex...
method getBlockingResult (line 61) | private String getBlockingResult() throws InterruptedException {
method getFuture (line 66) | private CompletableFuture<String> getFuture() {
FILE: javalin/src/test/java/io/javalin/routeoverview/TestRouteOverviewInJava.java
class TestRouteOverviewInJava (line 18) | public class TestRouteOverviewInJava {
method field_works (line 22) | @Test
method class_works (line 27) | @Test
method lambda_works (line 33) | @Test
class InnerHandlerImplementation (line 38) | private static class InnerHandlerImplementation implements Handler {
method handle (line 39) | @Override
FILE: javalin/src/test/java/io/javalin/routeoverview/VisualTest.java
class VisualTest (line 35) | public class VisualTest {
method main (line 39) | public static void main(String[] args) {
method setupJavalinRoutes (line 48) | static void setupJavalinRoutes(Javalin app) {
method wsMethodRef (line 89) | private static void wsMethodRef(WsConfig wsConfig) {
method methodReference (line 94) | private static void methodReference(Context context) {
class ImplementingClass (line 97) | private static class ImplementingClass implements Handler {
method handle (line 98) | @Override
class HandlerImplementation (line 103) | public static class HandlerImplementation implements Handler {
method handle (line 104) | @Override
class CrudHandlerImpl (line 109) | static class CrudHandlerImpl implements CrudHandler {
method getAll (line 110) | @Override
method getOne (line 113) | @Override
method create (line 116) | @Override
method update (line 119) | @Override
method delete (line 122) | @Override
FILE: javalin/src/test/java/io/javalin/testing/JavalinTestUtil.java
class JavalinTestUtil (line 28) | public class JavalinTestUtil {
method get (line 31) | public static Javalin get(Javalin app, String path, Handler handler) {
method post (line 38) | public static Javalin post(Javalin app, String path, Handler handler) {
method put (line 45) | public static Javalin put(Javalin app, String path, Handler handler) {
method put (line 52) | public static Javalin put(Javalin app, String path, Handler handler, R...
method patch (line 61) | public static Javalin patch(Javalin app, String path, Handler handler) {
method patch (line 68) | public static Javalin patch(Javalin app, String path, Handler handler,...
method delete (line 77) | public static Javalin delete(Javalin app, String path, Handler handler) {
method delete (line 84) | public static Javalin delete(Javalin app, String path, Handler handler...
method head (line 93) | public static Javalin head(Javalin app, String path, Handler handler) {
method options (line 100) | public static Javalin options(Javalin app, String path, Handler handle...
method options (line 107) | public static Javalin options(Javalin app, String path, Handler handle...
method get (line 117) | public static Javalin get(Javalin app, String path, Handler handler, R...
method post (line 126) | public static Javalin post(Javalin app, String path, Handler handler, ...
method before (line 136) | public static Javalin before(Javalin app, Handler handler) {
method before (line 143) | public static Javalin before(Javalin app, String path, Handler handler) {
method after (line 150) | public static Javalin after(Javalin app, Handler handler) {
method after (line 157) | public static Javalin after(Javalin app, String path, Handler handler) {
method exception (line 165) | public static <E extends Exception> Javalin exception(Javalin app, Cla...
method error (line 171) | public static Javalin error(Javalin app, int status, Handler handler) {
method sse (line 177) | public static Javalin sse(Javalin app, String path, Consumer<SseClient...
method ws (line 185) | public static Javalin ws(Javalin app, String path, Consumer<WsConfig> ...
method wsException (line 191) | public static <E extends Exception> Javalin wsException(Javalin app, C...
method wsAfter (line 197) | public static Javalin wsAfter(Javalin app, Consumer<WsConfig> wsConfig) {
method wsAfter (line 202) | public static Javalin wsAfter(Javalin app, String path, Consumer<WsCon...
method wsBefore (line 207) | public static Javalin wsBefore(Javalin app, Consumer<WsConfig> wsConfi...
method wsBefore (line 212) | public static Javalin wsBefore(Javalin app, String path, Consumer<WsCo...
FILE: javalin/src/test/java/io/javalin/testing/NonSerializableObject.java
class NonSerializableObject (line 3) | public class NonSerializableObject {
FILE: javalin/src/test/java/io/javalin/testing/RunResult.java
class RunResult (line 3) | public class RunResult {
method RunResult (line 7) | public RunResult(String logs, Exception exception) {
FILE: javalin/src/test/java/io/javalin/testing/SerializableObject.java
class SerializableObject (line 5) | public class SerializableObject implements Serializable {
FILE: javalin/src/test/java/io/javalin/testing/TestServlet.java
class TestServlet (line 16) | public class TestServlet extends HttpServlet {
method doGet (line 17) | public void doGet(HttpServletRequest req, HttpServletResponse res) thr...
FILE: javalin/src/test/java/io/javalin/testing/TestUtil.java
class TestUtil (line 20) | public class TestUtil {
method test (line 28) | public static void test(ThrowingBiConsumer<Javalin, HttpUtil> test) {
method test (line 32) | public static void test(Javalin app, ThrowingBiConsumer<Javalin, HttpU...
method testWithResult (line 36) | public static RunResult testWithResult(ThrowingBiConsumer<Javalin, Htt...
method testWithResult (line 40) | public static RunResult testWithResult(Javalin app, ThrowingBiConsumer...
method runAndCaptureLogs (line 61) | public static RunResult runAndCaptureLogs(Runnable testCode) {
method runLogLess (line 85) | public static void runLogLess(Runnable run) {
method captureStdOut (line 93) | public static String captureStdOut(Runnable run) {
FILE: javalin/src/test/java/io/javalin/testing/ThrowingBiConsumer.java
type ThrowingBiConsumer (line 11) | @FunctionalInterface
method accept (line 13) | @Override
method acceptThrows (line 22) | void acceptThrows(T t, U u) throws Exception;
FILE: javalin/src/test/java/io/javalin/testing/TypedException.java
class TypedException (line 10) | public class TypedException extends Exception {
method proofOfType (line 11) | public String proofOfType() {
FILE: javalin/src/test/resources/public/module.mjs
function test (line 1) | function test() {
Condensed preview — 491 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,766K chars).
[
{
"path": ".editorconfig",
"chars": 508,
"preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 4\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
},
{
"path": ".github/README.md",
"chars": 9109,
"preview": "<a name=\"readme-top\"></a>\n\n<div align=\"center\">\n\n <!--Logo-->\n <a href=\"https://github.com/javalin/javalin\">\n <img "
},
{
"path": ".github/copilot-instructions.md",
"chars": 25533,
"preview": "# Javalin Web Framework\n\nJavalin is a lightweight web framework for Java and Kotlin built on top of Jetty. This is a mul"
},
{
"path": ".github/dependabot.yml",
"chars": 661,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"maven\"\n directory: \"/\"\n schedule:\n interval: \"monthly\"\n time"
},
{
"path": ".github/workflows/cleanup-performance-preview.yml",
"chars": 1034,
"preview": "name: Cleanup Performance Preview\n\non:\n pull_request:\n types:\n - closed\n\npermissions:\n contents: read\n\njobs:\n "
},
{
"path": ".github/workflows/main.yml",
"chars": 2266,
"preview": "name: Test all JDKs on all OSes\n\non: [push, pull_request]\n\njobs:\n build:\n\n runs-on: ${{ matrix.os }}\n strategy:\n "
},
{
"path": ".github/workflows/publish-snapshots.yml",
"chars": 941,
"preview": "name: Snapshot build\n\non:\n push:\n branches: [ 'master' ]\n\njobs:\n publish:\n if: |\n github.repository == 'jav"
},
{
"path": ".github/workflows/test-performance-command.yml",
"chars": 7034,
"preview": "name: Test performance command\n\non:\n issue_comment:\n types:\n - created\n\npermissions:\n contents: read\n pull-re"
},
{
"path": ".gitignore",
"chars": 423,
"preview": "target/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\npom.xml.next\nrelease.properties\ndependency-reduced-pom."
},
{
"path": ".mvn/wrapper/maven-wrapper.properties",
"chars": 1019,
"preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the NOTICE f"
},
{
"path": "LICENSE",
"chars": 11338,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1119,
"preview": " # Javalin\nThis readme is for Javalin developers. \nIf you are looking for the general readme, see [.github/README.md](.g"
},
{
"path": "jacoco-coverage-report/README.md",
"chars": 1221,
"preview": "# Jacoco Coverage Report\n\nThis module is used for Jacoco code coverage report aggregation.\n\n## Jacoco Report Path\n\nThe J"
},
{
"path": "jacoco-coverage-report/pom.xml",
"chars": 4373,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "javalin/module-info.java",
"chars": 1631,
"preview": "module io.javalin {\n\n exports io.javalin;\n exports io.javalin.apibuilder;\n exports io.javalin.compression;\n "
},
{
"path": "javalin/pom.xml",
"chars": 10396,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "javalin/src/main/java/io/javalin/Javalin.java",
"chars": 4578,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/apibuilder/ApiBuilder.java",
"chars": 26279,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/apibuilder/CrudHandler.kt",
"chars": 608,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/apibuilder/EndpointGroup.java",
"chars": 264,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/compression/Brotli.kt",
"chars": 318,
"preview": "package io.javalin.compression\n\n/** Configuration for Brotli compression\n * @param level Compression level. Higher yield"
},
{
"path": "javalin/src/main/java/io/javalin/compression/Brotli4jCompressor.kt",
"chars": 800,
"preview": "package io.javalin.compression\n\n\nimport com.aayushatharva.brotli4j.encoder.BrotliOutputStream\nimport com.aayushatharva.b"
},
{
"path": "javalin/src/main/java/io/javalin/compression/CompressedStream.kt",
"chars": 2134,
"preview": "package io.javalin.compression\n\nimport io.javalin.http.Context\nimport io.javalin.http.Header\nimport jakarta.servlet.Serv"
},
{
"path": "javalin/src/main/java/io/javalin/compression/CompressionStrategy.kt",
"chars": 7431,
"preview": "package io.javalin.compression\n\nimport com.aayushatharva.brotli4j.Brotli4jLoader\nimport io.javalin.util.CoreDependency\ni"
},
{
"path": "javalin/src/main/java/io/javalin/compression/CompressionType.kt",
"chars": 198,
"preview": "package io.javalin.compression\n\nenum class CompressionType(val typeName: String, val extension: String) {\n GZIP(\"gzip"
},
{
"path": "javalin/src/main/java/io/javalin/compression/Compressor.kt",
"chars": 660,
"preview": "package io.javalin.compression\n\nimport java.io.OutputStream\n\n/** A compressor is used to compress an output stream */\nin"
},
{
"path": "javalin/src/main/java/io/javalin/compression/Gzip.kt",
"chars": 311,
"preview": "package io.javalin.compression\n\n/** Configuration for Gzip compression\n * @param level Compression level. Higher yields "
},
{
"path": "javalin/src/main/java/io/javalin/compression/GzipCompressor.kt",
"chars": 693,
"preview": "package io.javalin.compression\n\nimport java.io.OutputStream\nimport java.util.zip.GZIPOutputStream\n\n/** @param level Comp"
},
{
"path": "javalin/src/main/java/io/javalin/compression/Zstd.kt",
"chars": 313,
"preview": "package io.javalin.compression\n\n/** Configuration for Zstd compression\n * @param level Compression level. Higher yields "
},
{
"path": "javalin/src/main/java/io/javalin/compression/ZstdCompressor.kt",
"chars": 598,
"preview": "package io.javalin.compression\n\nimport com.github.luben.zstd.ZstdOutputStream\nimport java.io.OutputStream\n\n/** @param le"
},
{
"path": "javalin/src/main/java/io/javalin/config/AppDataManager.kt",
"chars": 727,
"preview": "package io.javalin.config\n\ndata class Key<T>(val id: String)\n\nclass KeyAlreadyExistsException(key: Key<*>) : IllegalStat"
},
{
"path": "javalin/src/main/java/io/javalin/config/BundledPluginsConfig.kt",
"chars": 2874,
"preview": "package io.javalin.config\n\nimport io.javalin.plugin.bundled.BasicAuthPlugin\nimport io.javalin.plugin.bundled.CorsPlugin\n"
},
{
"path": "javalin/src/main/java/io/javalin/config/ConcurrencyConfig.kt",
"chars": 510,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/config/ContextResolverConfig.kt",
"chars": 1210,
"preview": "package io.javalin.config\n\nimport io.javalin.http.Context\nimport io.javalin.http.Header\n\n/**\n * Configure the implementa"
},
{
"path": "javalin/src/main/java/io/javalin/config/EventConfig.kt",
"chars": 2712,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/config/HttpConfig.kt",
"chars": 744,
"preview": "package io.javalin.config\n\nimport io.javalin.compression.CompressionStrategy\nimport io.javalin.http.ContentType\n\n/**\n * "
},
{
"path": "javalin/src/main/java/io/javalin/config/JavalinConfig.kt",
"chars": 2476,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/config/JavalinState.kt",
"chars": 5571,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/config/JettyConfig.kt",
"chars": 2804,
"preview": "package io.javalin.config\n\nimport org.eclipse.jetty.ee10.servlet.ServletContextHandler\nimport org.eclipse.jetty.ee10.ser"
},
{
"path": "javalin/src/main/java/io/javalin/config/JettyInternalConfig.kt",
"chars": 996,
"preview": "package io.javalin.config\n\nimport org.eclipse.jetty.ee10.servlet.ServletContextHandler\nimport org.eclipse.jetty.ee10.web"
},
{
"path": "javalin/src/main/java/io/javalin/config/MultipartConfig.kt",
"chars": 2630,
"preview": "package io.javalin.config\n\nimport jakarta.servlet.MultipartConfigElement\n\n/**\n * This class contains the configuration f"
},
{
"path": "javalin/src/main/java/io/javalin/config/RequestLoggerConfig.kt",
"chars": 767,
"preview": "package io.javalin.config\n\nimport io.javalin.http.RequestLogger\nimport io.javalin.websocket.WsConfig\nimport java.util.fu"
},
{
"path": "javalin/src/main/java/io/javalin/config/RouterConfig.kt",
"chars": 1593,
"preview": "@file:Suppress(\"internal\", \"INVISIBLE_REFERENCE\", \"INVISIBLE_MEMBER\")\n\npackage io.javalin.config\n\nimport io.javalin.http"
},
{
"path": "javalin/src/main/java/io/javalin/config/RoutesConfig.kt",
"chars": 2407,
"preview": "@file:Suppress(\"internal\", \"INVISIBLE_REFERENCE\", \"INVISIBLE_MEMBER\")\n\npackage io.javalin.config\n\nimport io.javalin.apib"
},
{
"path": "javalin/src/main/java/io/javalin/config/SpaRootConfig.kt",
"chars": 950,
"preview": "package io.javalin.config\n\nimport io.javalin.http.Handler\nimport io.javalin.http.SinglePageHandler\nimport io.javalin.htt"
},
{
"path": "javalin/src/main/java/io/javalin/config/StartupConfig.kt",
"chars": 411,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/config/StaticFilesConfig.kt",
"chars": 1972,
"preview": "package io.javalin.config\n\nimport io.javalin.http.Header\nimport io.javalin.http.staticfiles.Location\nimport io.javalin.h"
},
{
"path": "javalin/src/main/java/io/javalin/config/ValidationConfig.kt",
"chars": 855,
"preview": "package io.javalin.config\n\nclass ValidationConfig() {\n\n internal val converters = mutableMapOf<Class<*>, (String) -> "
},
{
"path": "javalin/src/main/java/io/javalin/event/EventManager.kt",
"chars": 3050,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/event/LifecycleEventListener.kt",
"chars": 519,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/ContentType.kt",
"chars": 4822,
"preview": "package io.javalin.http\n\n/**\n * List of mime types for the most common file types.\n *\n * Sources:\n * * [Mozilla / Common"
},
{
"path": "javalin/src/main/java/io/javalin/http/Context.kt",
"chars": 26500,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/Cookie.kt",
"chars": 4551,
"preview": "package io.javalin.http\n\nimport jakarta.servlet.http.HttpServletResponse\nimport jakarta.servlet.http.Cookie as ServletCo"
},
{
"path": "javalin/src/main/java/io/javalin/http/ExceptionHandler.java",
"chars": 836,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/Handler.java",
"chars": 916,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/HandlerType.java",
"chars": 3895,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/Header.kt",
"chars": 6486,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/HttpResponseException.kt",
"chars": 17165,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/HttpStatus.kt",
"chars": 13491,
"preview": "package io.javalin.http\n\n/** HTTP response status codes indicating whether a specific HTTP request has been successfully"
},
{
"path": "javalin/src/main/java/io/javalin/http/RequestLogger.java",
"chars": 792,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/SinglePageHandler.kt",
"chars": 2718,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/UploadedFile.kt",
"chars": 1089,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/DefaultTasks.kt",
"chars": 5244,
"preview": "package io.javalin.http.servlet\n\nimport io.javalin.http.HandlerType\nimport io.javalin.http.HandlerType.GET\nimport io.jav"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/JavalinServlet.kt",
"chars": 6076,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/JavalinServletContext.kt",
"chars": 11693,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/JavalinServletRequest.kt",
"chars": 465,
"preview": "package io.javalin.http.servlet\n\nimport jakarta.servlet.ServletInputStream\nimport jakarta.servlet.http.HttpServletReques"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/JavalinWsServletContext.kt",
"chars": 1611,
"preview": "package io.javalin.http.servlet\n\nimport io.javalin.security.RouteRole\nimport jakarta.servlet.http.HttpServletRequest\nimp"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/MaxRequestSize.kt",
"chars": 1041,
"preview": "package io.javalin.http.servlet\n\nimport io.javalin.config.Key\nimport io.javalin.http.HttpResponseException\nimport io.jav"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/ServletEntry.kt",
"chars": 226,
"preview": "package io.javalin.http.servlet\n\nimport jakarta.servlet.Servlet\nimport jakarta.servlet.ServletContainerInitializer\n\ndata"
},
{
"path": "javalin/src/main/java/io/javalin/http/servlet/Task.kt",
"chars": 512,
"preview": "package io.javalin.http.servlet\n\nimport io.javalin.http.Context\n\nenum class SubmitOrder {\n FIRST,\n LAST\n}\n\nfun int"
},
{
"path": "javalin/src/main/java/io/javalin/http/sse/Emitter.kt",
"chars": 1159,
"preview": "package io.javalin.http.sse\n\nimport jakarta.servlet.http.HttpServletResponse\nimport java.io.IOException\nimport java.io.I"
},
{
"path": "javalin/src/main/java/io/javalin/http/sse/SseClient.kt",
"chars": 2953,
"preview": "package io.javalin.http.sse\n\nimport io.javalin.http.Context\nimport io.javalin.json.toJsonString\nimport io.javalin.util.J"
},
{
"path": "javalin/src/main/java/io/javalin/http/sse/SseHandler.kt",
"chars": 997,
"preview": "package io.javalin.http.sse\n\nimport io.javalin.http.Context\nimport io.javalin.http.Handler\nimport io.javalin.http.Header"
},
{
"path": "javalin/src/main/java/io/javalin/http/staticfiles/JavalinStaticResourceHandler.kt",
"chars": 4893,
"preview": "package io.javalin.http.staticfiles\n\nimport io.javalin.compression.CompressionStrategy\nimport io.javalin.compression.Com"
},
{
"path": "javalin/src/main/java/io/javalin/http/staticfiles/ResourceHandler.java",
"chars": 621,
"preview": "package io.javalin.http.staticfiles;\n\nimport io.javalin.compression.CompressionStrategy;\nimport io.javalin.http.Context;"
},
{
"path": "javalin/src/main/java/io/javalin/http/staticfiles/StaticFileConfig.kt",
"chars": 3538,
"preview": "package io.javalin.http.staticfiles\n\nimport io.javalin.config.StaticFilesConfig\nimport io.javalin.http.ContentType\nimpor"
},
{
"path": "javalin/src/main/java/io/javalin/http/staticfiles/StaticFileHandler.kt",
"chars": 3294,
"preview": "package io.javalin.http.staticfiles\n\nimport io.javalin.http.ContentType\nimport io.javalin.http.Context\nimport io.javalin"
},
{
"path": "javalin/src/main/java/io/javalin/http/staticfiles/StaticResource.kt",
"chars": 4145,
"preview": "package io.javalin.http.staticfiles\n\nimport java.io.InputStream\nimport java.net.URL\nimport java.nio.file.Files\nimport ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/AsyncUtil.kt",
"chars": 3728,
"preview": "package io.javalin.http.util\n\nimport io.javalin.config.HttpConfig\nimport io.javalin.config.Key\nimport io.javalin.http.Co"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/CookieStore.kt",
"chars": 1872,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/ETagGenerator.kt",
"chars": 1359,
"preview": "package io.javalin.http.util\n\nimport io.javalin.http.Context\nimport io.javalin.http.HandlerType.GET\nimport io.javalin.ht"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/JsonEscapeUtil.kt",
"chars": 694,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/MethodNotAllowedUtil.kt",
"chars": 807,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/MultipartUtil.kt",
"chars": 3211,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/http/util/SeekableWriter.kt",
"chars": 2640,
"preview": "package io.javalin.http.util\n\nimport io.javalin.http.Context\nimport io.javalin.http.Header\nimport io.javalin.http.HttpSt"
},
{
"path": "javalin/src/main/java/io/javalin/jetty/JavalinJettyServlet.kt",
"chars": 5813,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/jetty/JettyPrecompressingResourceHandler.kt",
"chars": 2787,
"preview": "package io.javalin.jetty\n\nimport io.javalin.compression.CompressionStrategy\nimport io.javalin.compression.Compressor\nimp"
},
{
"path": "javalin/src/main/java/io/javalin/jetty/JettyResourceHandler.kt",
"chars": 6369,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/jetty/JettyServer.kt",
"chars": 9898,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/jetty/JettyUtil.kt",
"chars": 620,
"preview": "package io.javalin.jetty\n\nimport io.javalin.config.JavalinState\nimport io.javalin.http.servlet.ServletEntry\nimport io.ja"
},
{
"path": "javalin/src/main/java/io/javalin/json/JavalinGson.kt",
"chars": 2569,
"preview": "package io.javalin.json\n\nimport com.google.gson.Gson\nimport io.javalin.http.InternalServerErrorResponse\nimport io.javali"
},
{
"path": "javalin/src/main/java/io/javalin/json/JavalinJackson.kt",
"chars": 4027,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/json/JsonMapper.kt",
"chars": 3729,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/json/PipedStreamUtil.kt",
"chars": 1274,
"preview": "package io.javalin.json\n\nimport io.javalin.util.ConcurrencyUtil\nimport io.javalin.util.function.ThrowingConsumer\nimport "
},
{
"path": "javalin/src/main/java/io/javalin/plugin/PluginApi.kt",
"chars": 2190,
"preview": "package io.javalin.plugin\n\nimport io.javalin.config.JavalinState\nimport io.javalin.http.Context\nimport java.util.functio"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/PluginExceptions.kt",
"chars": 570,
"preview": "package io.javalin.plugin\n\nimport io.javalin.util.JavalinException\n\nabstract class PluginException(pluginClass: Class<ou"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/PluginManager.kt",
"chars": 1519,
"preview": "package io.javalin.plugin\n\nimport io.javalin.config.JavalinState\n\nclass PluginManager internal constructor(private val c"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/BasicAuthPlugin.kt",
"chars": 1258,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/CorsPlugin.kt",
"chars": 7045,
"preview": "package io.javalin.plugin.bundled\n\nimport io.javalin.config.JavalinState\nimport io.javalin.http.Context\nimport io.javali"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/CorsUtils.kt",
"chars": 4360,
"preview": "package io.javalin.plugin.bundled\n\nimport java.net.URI\nimport java.util.*\n\ninternal object CorsUtils {\n\n /**\n * r"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/DevLoggerPlugin.kt",
"chars": 6304,
"preview": "package io.javalin.plugin.bundled\n\nimport io.javalin.config.JavalinState\nimport io.javalin.http.Context\nimport io.javali"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/GlobalHeadersPlugin.kt",
"chars": 14736,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2021 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/HttpAllowedMethodsPlugin.kt",
"chars": 1647,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2021 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/JavalinVuePlugin.kt",
"chars": 689,
"preview": "package io.javalin.plugin.bundled\n\nimport io.javalin.config.JavalinState\nimport io.javalin.plugin.Plugin\nimport io.javal"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/RateLimitPlugin.kt",
"chars": 3674,
"preview": "package io.javalin.plugin.bundled\n\nimport io.javalin.http.Context\nimport io.javalin.http.HttpResponseException\nimport io"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/RedirectToLowercasePathPlugin.kt",
"chars": 4149,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/RouteOverviewPlugin.kt",
"chars": 1557,
"preview": "package io.javalin.plugin.bundled\n\nimport io.javalin.config.JavalinState\nimport io.javalin.http.ContentType\nimport io.ja"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/RouteOverviewUtil.kt",
"chars": 8296,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/plugin/bundled/SslRedirectPlugin.kt",
"chars": 2004,
"preview": "package io.javalin.plugin.bundled\n\nimport io.javalin.config.JavalinState\nimport io.javalin.http.Header\nimport io.javalin"
},
{
"path": "javalin/src/main/java/io/javalin/rendering/FileRenderer.kt",
"chars": 856,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/router/Endpoint.kt",
"chars": 2461,
"preview": "package io.javalin.router\n\nimport io.javalin.http.Context\nimport io.javalin.http.Handler\nimport io.javalin.http.HandlerT"
},
{
"path": "javalin/src/main/java/io/javalin/router/Endpoints.kt",
"chars": 2926,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/router/HandlerWrapper.kt",
"chars": 135,
"preview": "package io.javalin.router\n\nimport io.javalin.http.Handler\n\nfun interface HandlerWrapper {\n fun wrap(endpoint: Endpoin"
},
{
"path": "javalin/src/main/java/io/javalin/router/InternalRouter.kt",
"chars": 6104,
"preview": "package io.javalin.router\n\nimport io.javalin.config.JettyConfig\nimport io.javalin.config.RouterConfig\nimport io.javalin."
},
{
"path": "javalin/src/main/java/io/javalin/router/JavalinDefaultRoutingApi.kt",
"chars": 15263,
"preview": "package io.javalin.router\n\nimport io.javalin.http.ExceptionHandler\nimport io.javalin.http.Handler\nimport io.javalin.http"
},
{
"path": "javalin/src/main/java/io/javalin/router/ParsedEndpoint.kt",
"chars": 936,
"preview": "package io.javalin.router\n\nimport io.javalin.config.RouterConfig\nimport io.javalin.http.servlet.JavalinServletContext\nim"
},
{
"path": "javalin/src/main/java/io/javalin/router/error/ErrorMapper.kt",
"chars": 1048,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/router/exception/ExceptionMapper.kt",
"chars": 3826,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/router/exception/HttpResponseExceptionMapper.kt",
"chars": 3578,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/router/exception/JavaLangErrorHandler.kt",
"chars": 178,
"preview": "package io.javalin.router.exception\n\nimport jakarta.servlet.http.HttpServletResponse\n\nfun interface JavaLangErrorHandler"
},
{
"path": "javalin/src/main/java/io/javalin/router/matcher/ParserExceptions.kt",
"chars": 600,
"preview": "package io.javalin.router.matcher\n\nclass MissingBracketsException(segment: String, val path: String) : IllegalArgumentEx"
},
{
"path": "javalin/src/main/java/io/javalin/router/matcher/ParserState.kt",
"chars": 4701,
"preview": "package io.javalin.router.matcher\n\nimport io.javalin.router.matcher.ParserState.INSIDE_SLASH_ACCEPTING_BRACKETS\nimport i"
},
{
"path": "javalin/src/main/java/io/javalin/router/matcher/PathMatcher.kt",
"chars": 2447,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/router/matcher/PathParser.kt",
"chars": 3185,
"preview": "package io.javalin.router.matcher\n\nimport io.javalin.config.RouterConfig\nimport io.javalin.http.servlet.urlDecode\n\nclass"
},
{
"path": "javalin/src/main/java/io/javalin/router/matcher/PathSegment.kt",
"chars": 3358,
"preview": "package io.javalin.router.matcher\n\nimport io.javalin.router.matcher.PathSegment.MultipleSegments\nimport io.javalin.route"
},
{
"path": "javalin/src/main/java/io/javalin/router/matcher/RoutingRegexes.kt",
"chars": 1651,
"preview": "package io.javalin.router.matcher\n\nimport io.javalin.config.RouterConfig\nimport io.javalin.router.matcher.PathSegment.Wi"
},
{
"path": "javalin/src/main/java/io/javalin/security/BasicAuthCredentials.kt",
"chars": 304,
"preview": "package io.javalin.security\n\n/**\n * Auth credentials for basic HTTP authorization.\n * Contains the Base64 decoded [usern"
},
{
"path": "javalin/src/main/java/io/javalin/security/RouteRole.kt",
"chars": 462,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/util/ConcurrencyUtil.kt",
"chars": 5668,
"preview": "package io.javalin.util\n\nimport org.eclipse.jetty.util.thread.QueuedThreadPool\nimport org.eclipse.jetty.util.thread.Thre"
},
{
"path": "javalin/src/main/java/io/javalin/util/FileUtil.kt",
"chars": 866,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/util/JavalinExceptions.kt",
"chars": 456,
"preview": "package io.javalin.util\n\nopen class JavalinException : RuntimeException {\n constructor(message: String) : super(messa"
},
{
"path": "javalin/src/main/java/io/javalin/util/JavalinLogger.kt",
"chars": 1240,
"preview": "package io.javalin.util\n\nimport io.javalin.Javalin\nimport org.slf4j.LoggerFactory\n\n// @formatter:off\nobject JavalinLogge"
},
{
"path": "javalin/src/main/java/io/javalin/util/OptionalDependency.kt",
"chars": 2905,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/util/ReflectionUtil.kt",
"chars": 1355,
"preview": "package io.javalin.util\n\ninternal val Any.kotlinFieldName // this is most likely a very stupid solution\n get() = this"
},
{
"path": "javalin/src/main/java/io/javalin/util/Util.kt",
"chars": 4450,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/util/function/ThrowingConsumer.java",
"chars": 213,
"preview": "package io.javalin.util.function;\n\n/** Throwing version of {@link java.util.function.Consumer} */\n@FunctionalInterface\np"
},
{
"path": "javalin/src/main/java/io/javalin/util/function/ThrowingRunnable.java",
"chars": 194,
"preview": "package io.javalin.util.function;\n\n/** Throwing version of {@link java.lang.Runnable} */\n@FunctionalInterface\npublic int"
},
{
"path": "javalin/src/main/java/io/javalin/util/legacy/LegacyAccessManager.kt",
"chars": 930,
"preview": "package io.javalin.util.legacy\n\nimport io.javalin.Javalin\nimport io.javalin.http.Context\nimport io.javalin.http.Handler\n"
},
{
"path": "javalin/src/main/java/io/javalin/validation/BodyValidator.kt",
"chars": 1158,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/validation/Validation.kt",
"chars": 2425,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/validation/Validator.kt",
"chars": 3693,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/vue/JavalinVueConfig.kt",
"chars": 1941,
"preview": "package io.javalin.vue\n\nimport io.javalin.config.JavalinState\nimport io.javalin.config.Key\nimport io.javalin.http.Contex"
},
{
"path": "javalin/src/main/java/io/javalin/vue/LoadableData.kt",
"chars": 3421,
"preview": "package io.javalin.vue\n\nconst val loadableDataScript = \"\"\"\n\n<script nonce=\"@internalAddNonce\">\n class LoadableData {\n"
},
{
"path": "javalin/src/main/java/io/javalin/vue/VueComponent.kt",
"chars": 647,
"preview": "package io.javalin.vue\n\nimport io.javalin.http.Context\n\nclass VueComponent @JvmOverloads constructor(\n val component:"
},
{
"path": "javalin/src/main/java/io/javalin/vue/VueDependencyResolver.java",
"chars": 5058,
"preview": "/*\n * Copyright 2020 tareq.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use thi"
},
{
"path": "javalin/src/main/java/io/javalin/vue/VueFileInliner.kt",
"chars": 1389,
"preview": "package io.javalin.vue\n\nimport io.javalin.util.javalinLazy\nimport java.nio.file.Path\nimport java.util.regex.Matcher\n\nint"
},
{
"path": "javalin/src/main/java/io/javalin/vue/VueHandler.kt",
"chars": 3808,
"preview": "package io.javalin.vue\n\nimport io.javalin.http.Context\nimport io.javalin.http.Handler\nimport io.javalin.http.Header\nimpo"
},
{
"path": "javalin/src/main/java/io/javalin/vue/VuePathMaster.kt",
"chars": 1938,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/vue/VueRenderer.kt",
"chars": 258,
"preview": "package io.javalin.vue\n\nimport io.javalin.http.Context\n\nopen class VueRenderer {\n open fun preRender(layout: String, "
},
{
"path": "javalin/src/main/java/io/javalin/vue/VueStateRenderer.kt",
"chars": 1322,
"preview": "package io.javalin.vue\n\nimport io.javalin.http.Context\nimport io.javalin.json.toJsonString\nimport io.javalin.vue.Javalin"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsAutomaticPing.kt",
"chars": 1076,
"preview": "package io.javalin.websocket\n\nimport io.javalin.util.ConcurrencyUtil\nimport io.javalin.util.javalinLazy\nimport java.nio."
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsCloseStatus.kt",
"chars": 3674,
"preview": "package io.javalin.websocket\n\n/**\n * WebSocket connection close codes.\n *\n * @see <a href=\"https://developer.mozilla.org"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsConfig.java",
"chars": 2514,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsConnection.kt",
"chars": 4024,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsContext.kt",
"chars": 8472,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsExceptionHandler.java",
"chars": 572,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsExceptionMapper.kt",
"chars": 1113,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsHandlers.kt",
"chars": 815,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsPathMatcher.kt",
"chars": 2154,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsRouter.kt",
"chars": 727,
"preview": "package io.javalin.websocket\n\nimport io.javalin.config.RouterConfig\nimport io.javalin.security.RouteRole\nimport java.uti"
},
{
"path": "javalin/src/main/java/io/javalin/websocket/WsUpgradeLogger.java",
"chars": 881,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/external/html.html",
"chars": 139,
"preview": "<html>\n <head>\n <link rel=\"stylesheet\" href=\"styles.css\">\n </head>\n <body>\n <h1>HTML works</h1>\n "
},
{
"path": "javalin/src/test/external/txt.txt",
"chars": 12,
"preview": "Sample text\n"
},
{
"path": "javalin/src/test/java/io/javalin/LargeSeekableInput.kt",
"chars": 862,
"preview": "package io.javalin\n\nimport java.io.InputStream\n\nclass LargeSeekableInput(private val prefixSize: Long, private val conte"
},
{
"path": "javalin/src/test/java/io/javalin/TestApiBuilder.kt",
"chars": 20274,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestApiBuilderWebSocket.java",
"chars": 1714,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestAppData.kt",
"chars": 2737,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestBeforeAfterMatched.kt",
"chars": 17721,
"preview": "package io.javalin\n\nimport io.javalin.http.ContentType\nimport io.javalin.http.HttpStatus\nimport io.javalin.http.Header\ni"
},
{
"path": "javalin/src/test/java/io/javalin/TestBeforeMatched.kt",
"chars": 3200,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestBodyReading.kt",
"chars": 6372,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestClose.kt",
"chars": 1616,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestClose_Java.java",
"chars": 2337,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestCompression.kt",
"chars": 33858,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestConcurrencyUtil.kt",
"chars": 5282,
"preview": "package io.javalin\n\nimport io.javalin.util.ConcurrencyUtil\nimport io.javalin.util.NamedThreadFactory\nimport io.javalin.u"
},
{
"path": "javalin/src/test/java/io/javalin/TestConfiguration.kt",
"chars": 5800,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestConfigureServletContextHandler.kt",
"chars": 2682,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestContextHandlerType.java",
"chars": 1256,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2021 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestContextPath.kt",
"chars": 3546,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestContextRouteRoles.kt",
"chars": 2301,
"preview": "package io.javalin\n\nimport io.javalin.Role.A\nimport io.javalin.Role.B\nimport io.javalin.Role.C\nimport io.javalin.Role.D"
},
{
"path": "javalin/src/test/java/io/javalin/TestCookie.kt",
"chars": 6892,
"preview": "package io.javalin\n\nimport io.javalin.http.Cookie\nimport io.javalin.http.Header\nimport io.javalin.http.HttpStatus\nimpor"
},
{
"path": "javalin/src/test/java/io/javalin/TestCookieStore.kt",
"chars": 4876,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestCors.kt",
"chars": 28795,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestCorsUtils.kt",
"chars": 8143,
"preview": "package io.javalin\n\nimport io.javalin.plugin.bundled.CorsUtils\nimport io.javalin.plugin.bundled.OriginParts\nimport io.ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestCustomJetty.kt",
"chars": 12449,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestCustomJettyHttpConfiguration.kt",
"chars": 3973,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestCustomRequestLifecycle.kt",
"chars": 1762,
"preview": "package io.javalin\n\nimport io.javalin.http.Context\nimport io.javalin.http.servlet.DefaultTasks.HTTP\nimport io.javalin.h"
},
{
"path": "javalin/src/test/java/io/javalin/TestDependencyUtil.kt",
"chars": 940,
"preview": "package io.javalin\n\nimport io.javalin.util.CoreDependency\nimport io.javalin.util.DependencyUtil\nimport org.assertj.core."
},
{
"path": "javalin/src/test/java/io/javalin/TestEncoding.kt",
"chars": 5026,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestEndpoint.kt",
"chars": 3038,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestErrorMapper.kt",
"chars": 3204,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestEtags.kt",
"chars": 3697,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestEventManager.kt",
"chars": 2732,
"preview": "package io.javalin\n\nimport io.javalin.event.EventManager\nimport io.javalin.event.HandlerMetaInfo\nimport io.javalin.event"
},
{
"path": "javalin/src/test/java/io/javalin/TestExceptionMapper.kt",
"chars": 6796,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestFilters.kt",
"chars": 3697,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestFuture.kt",
"chars": 17620,
"preview": "package io.javalin\n\nimport io.javalin.http.Context\nimport io.javalin.http.HttpStatus\nimport io.javalin.http.HttpStatus."
},
{
"path": "javalin/src/test/java/io/javalin/TestGlobalGlobalHeaderConfigPlugin.kt",
"chars": 5996,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2021 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestGracefulShutdown.java",
"chars": 3204,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/ja"
},
{
"path": "javalin/src/test/java/io/javalin/TestHandlerWrapper.kt",
"chars": 3928,
"preview": "package io.javalin\n\nimport io.javalin.http.Context\nimport io.javalin.http.Handler\nimport io.javalin.testing.TestUtil\nimp"
},
{
"path": "javalin/src/test/java/io/javalin/TestHttpAllowedMethodsPlugin.kt",
"chars": 1850,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
},
{
"path": "javalin/src/test/java/io/javalin/TestHttpResponseExceptions.kt",
"chars": 15133,
"preview": "/*\n * Javalin - https://javalin.io\n * Copyright 2017 David Åse\n * Licensed under Apache 2.0: https://github.com/tipsy/j"
}
]
// ... and 291 more files (download for full content)
About this extraction
This page contains the full source code of the javalin/javalin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 491 files (1.6 MB), approximately 418.2k tokens, and a symbol index with 357 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.