GH-49 Dynamic API#284
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a backend-agnostic OpenAPI/JSON Schema generation pipeline (shared across annotation processing, KSP, and runtime reflection) and adds a runtime “hook” mechanism to let OpenApiPlugin enrich the served document with dynamically registered Javalin routes.
Changes:
- Added a new
introspectionsubsystem (API + runtime + JAP + KSP backends) to support schema generation from different compile/runtime environments. - Moved/rewired schema generation into
openapi-generatorso APT/Kapt, KSP, and reflection can share the same generator. - Added
openapi-ksp(KSP processor),openapi-dynamic(reflection context), and ajavalin-openapi-dynamic-hookplugin hook + docs/examples.
Reviewed changes
Copilot reviewed 95 out of 97 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle.kts | Registers new modules for introspection, KSP, dynamic generation, and examples |
| openapi-specification/src/main/kotlin/io/javalin/openapi/OpenApiStatus.kt | Adds HTTP status constants + reason phrase lookup used for default response descriptions |
| openapi-ksp/src/test/kotlin/io/javalin/openapi/ksp/OpenApiSymbolProcessorTest.kt | KSP processor integration tests (schema + OpenAPI resource generation) |
| openapi-ksp/src/test/kotlin/io/javalin/openapi/ksp/KspSchemaContextTest.kt | End-to-end KSP resolver-based schema generation test |
| openapi-ksp/src/test/kotlin/io/javalin/openapi/ksp/fixtures/User.kt | KSP schema fixture type |
| openapi-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider | Registers the KSP SymbolProcessorProvider |
| openapi-ksp/src/main/kotlin/io/javalin/openapi/ksp/OpenApiSymbolProcessor.kt | Implements KSP-based OpenAPI + JSON schema resource generation |
| openapi-ksp/src/main/kotlin/io/javalin/openapi/ksp/KspSchemaContext.kt | KSP-backed SchemaGenerationContext wiring |
| openapi-ksp/build.gradle.kts | Adds dependencies for KSP backend and compile-testing |
| openapi-generator/src/test/kotlin/io/javalin/openapi/schema/OpenApiSchemaBuilderTest.kt | Updates tests to use the new shared OpenApiType model |
| openapi-generator/src/main/kotlin/io/javalin/openapi/schema/OpenApiSchemaGenerator.kt | New shared OpenAPI document generator (route-map input) |
| openapi-generator/src/main/kotlin/io/javalin/openapi/schema/OpenApiSchemaBuilder.kt | Updates schema builder to use OpenApiType references |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/SimpleType.kt | Adds SimpleType model + opt-in annotation |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/SchemaGenerationContext.kt | Defines backend-agnostic schema generation interface |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/TypeSchemaGenerator.kt | Shared type→schema generator logic (now backend-agnostic) |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/ResultScheme.kt | Shared generator result model (json + references) |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/PropertyComposition.kt | Updates composition/discriminator model to use OpenApiType |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/ExampleGenerator.kt | Moves example mapping to Map-based representation |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/CompositionGenerator.kt | New shared composition generator (oneOf/anyOf/allOf + discriminator) |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/OpenApiType.kt | Renames/introduces OpenApiType model (with internal handle opt-in) |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/IntrospectorSchemaContext.kt | Base context for introspector-backed schema generation |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/EmbeddedTypeProcessor.kt | New embedded type processor API for pluggable schema handling |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/defaults/DictionaryEmbeddedTypeProcessor.kt | Fixes processor lookup to use embeddedTypeProcessors directly |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/defaults/DefaultEmbeddedTypeProcessors.kt | Provides default embedded type processor list factory |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/defaults/CompositionEmbeddedTypeProcessor.kt | Adds default processor to emit compositions |
| openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/defaults/ArrayEmbeddedTypeProcessor.kt | Cleans unused import; participates in default processor set |
| openapi-generator/build.gradle.kts | Adds introspection-api dependency to generator |
| openapi-dynamic/src/test/kotlin/io/javalin/openapi/dynamic/ReflectionSchemaContextTest.kt | Reflection backend tests for schema generation behavior |
| openapi-dynamic/src/test/kotlin/io/javalin/openapi/dynamic/DynamicSchemaGeneratorTest.kt | Tests component graph resolution through builder using reflection |
| openapi-dynamic/src/test/kotlin/io/javalin/openapi/dynamic/DynamicCompositionTest.kt | Tests runtime composition behavior (incl. empty oneOf suppression) |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Validated.java | Reflection fixtures for validation + redirect |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/TransientDto.java | Reflection fixtures for transient-field handling |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/SnakeCaseDto.java | Reflection fixtures for naming strategy |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Shape.java | Reflection fixtures for composition annotations |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Role.java | Reflection enum fixture for renamed constants |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/NotNull.java | Runtime-retained NotNull stand-in for name-based matching |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/FieldsDto.java | Reflection fixture for by-fields selection |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Dog.java | Composition subtype fixture |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Cat.java | Composition subtype fixture |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Address.java | Reflection nested-object fixture |
| openapi-dynamic/src/test/java/io/javalin/openapi/dynamic/fixtures/Account.java | Reflection feature-coverage fixture (ignore/rename/description/etc.) |
| openapi-dynamic/src/main/kotlin/io/javalin/openapi/dynamic/ReflectionSchemaContext.kt | Reflection-backed schema context implementation |
| openapi-dynamic/build.gradle.kts | Adds dependencies for reflection backend + tests |
| openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/ValidationAnnotationsTest.kt | Adds tests for validation keyword emission |
| openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/PropertySelectionTest.kt | Adds tests for ignore/by-fields selection behavior |
| openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/OperationAnnotationsTest.kt | Adds tests for parameters/request body/security/responses emission |
| openapi-annotation-processor/src/test/compile/openapi.groovy | Updates compile-time config script types/handles for OpenApiType |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/schema/OpenApiSchemaGenerator.kt | Removes old AP-specific schema generator (replaced by shared one) |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/processor/generators/OpenApiGenerator.kt | Switches annotation processor to shared generator and route-map model |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/processor/generators/JsonSchemaGenerator.kt | Uses new toOpenApiType path for schema generation |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/processor/shared/ModelExtensions.kt | Removes AP-only helpers now replaced by introspection APIs |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/processor/shared/AnnotationProcessorExtensions.kt | Removes unused MessagerWriter utility |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/TypeSchemaGenerator.kt | Removes AP-specific generator implementation (shared generator is used) |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/CompositionGenerator.kt | Removes AP-specific composition generator (shared generator is used) |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/OpenApiTypeHandle.kt | Adds OpenApiType handle utilities for AP backend |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/OpenApiAnnotationProcessorConfiguration.kt | Updates configuration to use OpenApiType + shared embedded processor defaults |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/ClassDefinitionHandle.kt | Removes old ClassDefinition handle utilities (replaced by OpenApiTypeHandle) |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/ClassDefinitionFactory.kt | Removes old ClassDefinition factory (replaced by introspection/JAP backend) |
| openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/AnnotationProcessorContext.kt | Implements SchemaGenerationContext via JAP introspector and OpenApiType mapping |
| openapi-annotation-processor/build.gradle.kts | Adds introspection-jap; removes direct Javalin dependency |
| javalin-plugins/javalin-openapi-plugin/src/main/kotlin/io/javalin/openapi/plugin/OpenApiPlugin.kt | Adds per-version runtime hook application during doc creation |
| javalin-plugins/javalin-openapi-plugin/src/main/kotlin/io/javalin/openapi/plugin/OpenApiConfiguration.kt | Introduces OpenApiHook/OpenApiHookContext + hook registration API |
| javalin-plugins/javalin-openapi-dynamic-hook/src/test/kotlin/io/javalin/openapi/dynamic/hook/DynamicOpenApiHookTest.kt | Tests route auto-discovery + metadata overlay behavior |
| javalin-plugins/javalin-openapi-dynamic-hook/src/test/java/io/javalin/openapi/dynamic/hook/fixtures/User.java | Fixture for metadata schema emission |
| javalin-plugins/javalin-openapi-dynamic-hook/src/main/kotlin/io/javalin/openapi/dynamic/hook/RegisteredRoutesHook.kt | Implements runtime route enumeration and OpenAPI document extension |
| javalin-plugins/javalin-openapi-dynamic-hook/src/main/kotlin/io/javalin/openapi/dynamic/hook/OpenApiMetadata.kt | Adds metadata container + schema(Class) helper for route enrichment |
| javalin-plugins/javalin-openapi-dynamic-hook/build.gradle.kts | Adds module wiring + runtime/test dependencies |
| introspection/introspection-test/src/test/kotlin/io/javalin/introspection/test/IntrospectionParityTest.kt | Adds parity tests across runtime and annotation-processing backends |
| introspection/introspection-test/src/test/kotlin/io/javalin/introspection/test/fixtures/Fixtures.kt | Test fixture types for introspection parity |
| introspection/introspection-test/src/test/kotlin/io/javalin/introspection/test/AnnotationProcessing.kt | Utility to run JAP backend inside in-process javac |
| introspection/introspection-test/src/test/java/io/javalin/introspection/test/sub/PackagePrivateBase.java | Fixture for cross-package inheritance behavior |
| introspection/introspection-test/src/test/java/io/javalin/introspection/test/Note.java | Fixture for repeatable annotation behavior |
| introspection/introspection-test/build.gradle.kts | Adds dependencies for parity tests |
| introspection/introspection-runtime/src/test/kotlin/io/javalin/introspection/runtime/ReflectionTypeIntrospectorTest.kt | Tests runtime reflection introspector behavior |
| introspection/introspection-runtime/src/main/kotlin/io/javalin/introspection/runtime/ReflectionTypeIntrospector.kt | Implements reflection TypeIntrospector backend |
| introspection/introspection-runtime/build.gradle.kts | Runtime introspector module build config |
| introspection/introspection-ksp/src/test/kotlin/io/javalin/introspection/ksp/KspTypeIntrospectorTest.kt | Tests KSP introspector behavior via compile-testing |
| introspection/introspection-ksp/src/test/kotlin/io/javalin/introspection/ksp/fixtures/Fixtures.kt | KSP fixture types |
| introspection/introspection-ksp/src/main/kotlin/io/javalin/introspection/ksp/KspTypeIntrospector.kt | Implements KSP TypeIntrospector backend |
| introspection/introspection-ksp/build.gradle.kts | KSP introspector module build config |
| introspection/introspection-jap/src/main/kotlin/io/javalin/introspection/jap/JapTypeIntrospector.kt | Implements JAP (javax.lang.model) TypeIntrospector backend |
| introspection/introspection-jap/build.gradle.kts | JAP introspector module build config |
| introspection/introspection-api/src/main/kotlin/io/javalin/introspection/TypeIntrospector.kt | Introduces TypeIntrospector abstraction |
| introspection/introspection-api/src/main/kotlin/io/javalin/introspection/PropertyView.kt | Adds PropertyView + accessor/visibility + getter-name utilities |
| introspection/introspection-api/src/main/kotlin/io/javalin/introspection/InternalIntrospectionApi.kt | Adds opt-in guard for backend-native source tokens |
| introspection/introspection-api/src/main/kotlin/io/javalin/introspection/CompileTimeIntrospector.kt | Adds compile-time extension (typesAnnotatedWith) |
| introspection/introspection-api/src/main/kotlin/io/javalin/introspection/ClassDefinition.kt | Introduces backend-agnostic type model + enum/property access |
| introspection/introspection-api/src/main/kotlin/io/javalin/introspection/Annotations.kt | Adds name/value-based annotation access + meta-annotation support |
| introspection/introspection-api/build.gradle.kts | Introspection API module build config |
| gradle/libs.versions.toml | Adds KSP + compile-testing dependencies and KSP Gradle plugin |
| examples/javalin-ksp-kotlin/src/main/resources/logback.xml | Example logging config |
| examples/javalin-ksp-kotlin/src/main/kotlin/io/javalin/openapi/ksp/example/App.kt | Adds example Kotlin app using KSP backend |
| examples/javalin-ksp-kotlin/build.gradle.kts | Adds KSP plugin config + ksp args for example |
| docs/introduction/setup.md | Documents Gradle KSP setup + backend selection guidance |
| docs/introduction/json-schema-setup.md | Documents KSP-based JsonSchema generation setup |
| docs/advanced/runtime-builder.md | Documents runtime hook module and metadata enrichment |
| docs/advanced/configuration.md | Documents KSP args + clarifies APT-only configuration features |
Comments suppressed due to low confidence (1)
openapi-generator/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/ResultScheme.kt:17
schema.put($$"$schema", ...)is invalid Kotlin syntax and will not compile. Use"\$schema"to emit the JSON Schema$schemakeyword.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
# Conflicts: # openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/experimental/processor/generators/TypeSchemaGenerator.kt
|
Oooh you're working on supporting ksp? Thats awesome! |
|
@lukashoegh well, this PR introduces a lot of things at once 😅 but yeah, ksp seems to be working just fine already: Let's see if I will manage to finish it, initially I was supposed to only provide the runtime (reflection based) backend, but to do it properly we should target all known possible targets as soon as possible to make sure that the abstraction layer does the trick 😬 |
4cc4a20 to
5bd3d1a
Compare
5bd3d1a to
2f05318
Compare
#49