{"id":33916875,"url":"https://github.com/cloudflightio/cloudflight-platform-spring","last_synced_at":"2026-04-09T04:04:24.951Z","repository":{"id":37965790,"uuid":"499118359","full_name":"cloudflightio/cloudflight-platform-spring","owner":"cloudflightio","description":"Cloudflight Platform for Spring","archived":false,"fork":false,"pushed_at":"2025-12-11T20:46:11.000Z","size":474,"stargazers_count":18,"open_issues_count":3,"forks_count":16,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-12-13T13:31:52.334Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudflightio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-06-02T12:02:54.000Z","updated_at":"2025-12-11T20:30:28.000Z","dependencies_parsed_at":"2023-09-26T16:28:17.465Z","dependency_job_id":"b42bd50c-b775-46bf-854b-57c5d79d3b19","html_url":"https://github.com/cloudflightio/cloudflight-platform-spring","commit_stats":null,"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"purl":"pkg:github/cloudflightio/cloudflight-platform-spring","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflightio%2Fcloudflight-platform-spring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflightio%2Fcloudflight-platform-spring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflightio%2Fcloudflight-platform-spring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflightio%2Fcloudflight-platform-spring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudflightio","download_url":"https://codeload.github.com/cloudflightio/cloudflight-platform-spring/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflightio%2Fcloudflight-platform-spring/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31584820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-12T07:33:59.175Z","updated_at":"2026-04-09T04:04:24.945Z","avatar_url":"https://github.com/cloudflightio.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cloudflight Platform for Spring Boot\n\n[![License](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Maven Central](https://img.shields.io/maven-central/v/io.cloudflight.platform.spring/platform-spring-bom.svg?label=Maven%20Central)](https://search.maven.org/artifact/io.cloudflight.platform.spring/platform-spring-bom)\n\n## Purpose\n\nThe Cloudflight Platform serves as foundation for all Cloudflight custom software projects running on the JVM. This contains\n3 major parts:\n\n- Unified **Dependency Management** on top of Spring Boot and Spring Cloud\n- **Utility Modules** for cross-cutting-concerns like monitoring, JPA access, Elastic Search and much more that can (and should) be embedded into your production code\n\n## Dependency Management \u0026 Usage\n\nThe Cloudflight Platform comes with two BOM packages (bill-of-materials) that provide dependency management for all\nplatform artifacts as well as third party libraries, one of them for application code, the other one for test-code.\n\nYou can utilize Gradle's dependency management and add both BOMs as platform-dependencies to your root project:\n\n````groovy\ndependencies {\n    api platform(\"io.cloudflight.platform.spring:platform-spring-bom:$cloudflightPlatformVersion\")\n    testImplementation platform(\"io.cloudflight.platform.spring:platform-spring-test-bom:$cloudflightPlatformVersion\")\n}\n````\n\nWhile `platform-bom` only provides dependency constraints, `platform-bom-test` also puts the following libaries to\nthe `testImplementation` classpath of **all** submodules of your project:\n\n* [JUnit 5](https://junit.org/junit5/) (including [JUnit-Params](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests))\n* [Mockk](https://mockk.io/)\n* [AssertJ](https://assertj.github.io/doc/)\n\nThat means you do not need to add them on your own. The Cloudflight Platform handles that for you.\n\nWhy exactly those? Because [not only we think that those are really valuable testing libraries](https://phauer.com/2018/best-practices-unit-testing-kotlin/).\n\nIn conjunction with the [AutoConfigure Gradle Plugin](https://github.com/cloudflightio/autoconfigure-gradle-plugin), you \nmight add code like that to your root `build.gradle`:\n\n````groovy\nsubprojects { proj -\u003e\n    dependencies {\n        api platform(\"io.cloudflight.platform.spring:platform-spring-bom:$cloudflightPlatformVersion\")\n        annotationProcessor platform(\"io.cloudflight.platform.spring:platform-spring-bom:$cloudflightPlatformVersion\")\n        if (proj.plugins.hasPlugin(org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper)) {\n            kapt platform(\"io.cloudflight.platform.spring:platform-spring-bom:$cloudflightPlatformVersion\")\n        }\n        testImplementation platform(\"io.cloudflight.platform.spring:platform-spring-test-bom:$cloudflightPlatformVersion\")\n    }\n}\n````\n\nBy adding the platform to your gradle root file, you can add any other submodule of the platform without entering the version number:\n\n````groovy\ndependencies {\n    testImplementation('io.cloudflight.platform.spring:platform-spring-jpa-test')\n}\n````\n\n## Production modules\n\nThese modules are meant to be embedded into your production code, either as api/implementation or as test dependency. Find more details\nabout the modules on the according subpages.\n\nEach module can be added to your code like that:\n\n````groovy\ndependencies {\n    implementation('io.cloudflight.platform.spring:%MODULE_NAME%')\n}\n````\n\ni.e.\n\n````groovy\ndependencies {\n    implementation('io.cloudflight.platform.spring:platform-spring-profiling')\n}\n````\n\n### Server Configuration\n\nWhenever you have a module in your code-base that fires up a Spring Boot Server (typically modules with the suffix\n`-server`), then add the module `io.cloudflight.platform.spring:platform-spring-server-config` to your `implementation` classpath.\n\n#### Server module identification\n\nIt not only adds other required modules for monitoring and logging config but also provides the interface\n`ServerModuleIdentification` as a Spring Bean which can be injected to your service. It provides you:\n\n* the name of the server\n* the current version (as provided from the build pipeline)\n* the underyling Git Hash.\n\n#### Startup time analysis\n\nWhen Spring Boot applications get bigger, startup time often decreases. In order to have more insights on what is going on,\nthe module `platform-server-config` comes with a utility which prints a detailled analysis of all startup phases of your\n`ApplicationContext`.\n\nTo enable that, you need to do two things:\n\n1. Set the logger `io.cloudflight.platform.spring.server.ApplicationStartupPrinter` to `TRACE`\n2. Set a `BufferingApplicationStartup` to your `SpringBootApplication` as described in the [official docs](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-application-startup-tracking).\n\n````java\npublic static void main(String[] args) {\n    SpringApplication app = new SpringApplication(MySpringConfiguration.class);\n    app.setApplicationStartup(new BufferingApplicationStartup(2048));\n    app.run(args);\n}\n````\n\nThe log itself gets quite huge and broad and would not fit into this documentation, but if you're interested, just try it out.\n\nIf you are running integration tests with `@SpringBootTest`, you don't need to set this bean manually. All you need to do is to ensure you have `platform-test` on your classpath.\n\n### Environment\n\nThe module `io.cloudflight.platform.spring:platform-spring-context` provides the object `ApplicationContextProfiles` which comes with\nconstants for our default [Spring profile](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-definition-profiles) names that will be put into the environment.\n\nThe profile names to be used then (also in `application.yaml` files) are the following:\n\n\n| Profile name                                                          | Description                                                                                                                                                                     | \n|---------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `development` | to be used for local development inside the IDE                                                                                                                                 |\n| `staging` | staging environment                                                                                                                                                             |\n| `production` | production environment                                                                                                                                                          |\n| `test` | default profile to be used in Spring Application tests                                                                                                                          |\n| `testcontainer` | To be used in test cases when using [TestContainers](https://www.testcontainers.org/), those tests run reasonabily slower and it should be possible to not run them explicitely |\n\n\nWhenever you are accessing one of those profile names from within the code (i.e. in a `@Profile` annotation), use the according contstant\nin `ApplicationContextProfiles`. Application configuration files need to be suffixed with the strings mentioned above (i.e. `application-development.yaml`).\n\n\n#### Monitoring Config\n\nMonitoring via Spring Boot Actuator and Prometheus will be activated automatically with the module\n`io.cloudflight.platform.spring:platform-spring-monitoring` (which comes together with `platform-server-config` as mentioned above).\n\nImportant thing to know here is that it automatically sets the port to listen for actuator requests to `server.port + 10000`.\nThat means, if your server is running on port 8080, you will find the actuator endpoints on 18080. We are doing this\nto provide a clean and easy-to-manage security concept for these endpoints in production as we can simply restrict\naccessing this port from outside and don't need to deal with Spring Security in parallel.\n\n#### Logging Config\n\nThe module `io.cloudflight.platform.spring:platform-spring-logging-server-config` (which is also being transitively loaded with)\n`platform-server-config` comes with a basic configuration for Logback, especially also preparing our logging mechanism\nfor the usage of the ELK stack on production.\n\nUse this file as reference in your `logback-spring.xml` files as follows:\n\n````xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cconfiguration\u003e\n  \u003cinclude resource=\"io/cloudflight/platform/spring/logging/clf-base.xml\" /\u003e\n\n  \u003clogger name=\"io.cloudflight\" level=\"INFO\"/\u003e\n\n  \u003croot level=\"WARN\"/\u003e\n\n\u003c/configuration\u003e\n````\n\n### Logging\n\nThe module `platform-logging` wraps [Slf4J](http://slf4.org) and [Kotlin Logging](https://github.com/MicroUtils/kotlin-logging) and also provides some annotations for more convenient\naccess for [MDC](https://www.baeldung.com/mdc-in-log4j-2-logback) values. MDC gives you the possibility to append\nstructured information to your log output which you can then easily filter and search in Kibana, see [this blog entry](https://www.baeldung.com/mdc-in-log4j-2-logback#mdc-in-slf4jlogback)\nfor more information.\n\n#### LogParam\n\nWhile this is a great thing, coding is a bit verbose as you need to manually take care to clear the MDC context after your method call.\nThe code example from the above linked blog entry is not fully correct, as you also need to catch exceptions properly and clean up\nin a `finally` block. That means, the correct usage would be (here now in kotlin code):\n\n````kotlin\nfun sayHello(name: String) {\n    try {\n        MDC.put(\"name\", name)\n        LOG.info(\"We are calling hello now\")\n    } finally {\n        MDC.remove(\"name\")\n    }\n}\n````\n\nWith `platform-spring-logging`, you get the annotation `io.cloudflight.platform.logging.annotation.LogParam` which you can append on method parameters. The\nfollowing code does exactly the same:\n\n````kotlin\nfun sayHello(@LogParam name: String) {\n    LOG.info(\"We are calling hello now\")\n}\n````\n\n:warning: We are using Spring AOP here, that means this only works for public methods of Spring beans (like any other Spring-related annotation like `@Transactional`).\n\nThe annotation `@LogParam` can also be customized and chained, here are some examples:\n\n````kotlin\n@Service\nclass MySpringBean {\n\n    fun sayHello(@LogParam name: String) {\n        // calls MDC.put(\"name\", name)\n    }\n\n    fun sayHelloWithNamedParameter(@LogParam(name = \"myName\") name: String) {\n        // calls MDC.put(\"myName\", name)\n    }\n\n    fun sayHelloWithField(@LogParam(field = \"firstName\") person: Person) {\n        // calls MDC.put(\"person.firstName\", person.firstName)\n    }\n\n    fun sayHelloWithFieldAndName(@LogParam(field = \"firstName\", name = \"myFirstName\") person: Person) {\n        // calls MDC.put(\"myFirstName\", person.firstName)\n    }\n\n    fun sayHelloWithMultipleFieldNames(\n        @LogParams(\n            LogParam(field = \"firstName\"),\n            LogParam(field = \"lastName\")\n        ) person: Person\n    ) {\n        // calls MDC.put(\"person.firstName\", person.firstName) and\n        // calls MDC.put(\"person.lastName\", person.lastName)\n    }\n\n    data class Person(val firstName: String, val lastName: String)\n}\n````\n\nPlease note that the underyling `io.cloudflight.platform.logging.interceptor.LogParamInterceptor` also takes care of cleaning\nup the MDC context again after the method call.\n\n#### mdcScope\n\nIf you cannot use `@LogParam` for some reason `platform-spring-logging` provides an additional convenient option.\n\nThe global function `mdcScope` keeps track of all fields MDC manipulations done in the passed lambda and cleans up for you afterwards.\n\n````kotlin\nfun sayHello(name: String) {\n    mdcScope {\n        MDC.put(\"name\", name)\n        MDC.put(\"name\" to name) // this is equivalent to the line above\n        LOG.info(\"We are calling hello now\")\n    }\n}\n````\n\nIf you need the `mdcScope` to cover your whole function you can also use it as a single-expression function:\n\n````kotlin\nfun sayHello(name: String) = mdcScope {\n    MDC.put(\"name\", name)\n    MDC.put(\"name\" to name) // this is equivalent to the line above\n    LOG.info(\"We are calling hello now\")\n}\n````\n\nPlease note that the `MDC` available inside the `mdcScope`-functions scope is not `org.slf4j.MDC` but a wrapper build around it.\n\n### JPA\n\nThe module `platform-spring-jpa` wraps all required libraries in order to access a relational database\nwith JPA/Hibernate and Spring Data, especially Spring's `spring-data-jpa` and Spring Boot's `spring-boot-starter-data-jpa`.\n\nIt also automatically applies `@EnableTransactionManagement`.\n\n#### QueryDSL Support\n\nIf you want to use [Query DSL](http://www.querydsl.com/static/querydsl/latest/reference/html/ch02.html#jpa_integration), then\n`platform-spring-jpa` autoconfigures a `JPQLQueryFactory` which you can use to create QueryDSL queries. Anyways,\nyou need to add QueryDSL to your classpath manually (it does not come by automatically), and also do not\nforget to apply the annotation processor.\n\nIf you are using Kotlin entities (which is our preferred way), then your `build.gradle` should look somehow like that:\n\n````groovy\ndependencies {\n    implementation 'io.cloudflight.platform.spring:platform-spring-jpa'\n    implementation 'com.querydsl:querydsl-jpa::jakarta'\n\n    kapt 'com.querydsl:querydsl-apt::jpa'\n    kapt 'io.cloudflight.platform.spring:platform-spring-jpa'\n}\n````\n\nThen, in order to use QueryDSL, create a [custom repository](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior) and inject the `JPQLQueryFactory`:\n\n````kotlin\ninterface ArtifactRepository : JpaRepository\u003cArtifact, Long\u003e, QueryDslArtifactRepository {  // \u003c1\u003e\n    fun findArtifactByProjectAndName(project: Project, name: String): Artifact?\n}\n\ninterface QueryDslArtifactRepository {                                                      // \u003c2\u003e\n    fun findAllByGroupId(groupId: String): List\u003cArtifactListDto\u003e\n}\n\n@Repository\nclass QueryDslArtifactRepositoryImpl(                                                       // \u003c3\u003e\n    private val queryFactory: JPQLQueryFactory                                              // \u003c4\u003e\n) : QueryDslArtifactRepository {\n\n    private val a = QArtifact.artifact\n\n    override fun findAllByGroupId(groupId: String): List\u003cArtifactListDto\u003e {\n        return queryFactory.select(QArtifactListDto(a.name, a.packaging))                   // \u003c5\u003e\n            .from(a)\n            .where(a.project.name.eq(groupId))\n            .fetch()\n    }\n}\n````\n\n1. Your default `JpaRepository` which extends from your custom repository interface\n2. Your custom repository interface with all methods that you want to query with QueryDSL\n3. Implementation of your custom repository\n4. Inject `JPQLQueryFactory`\n5. Use the `JPQLQueryFactory` to create your query instances\n\n### Caching\n\nThe module `platform-spring-caching` autoconfigures Redis Caches + Sessions for you. This happens automatically\nif it can find Redis on the classpath. You can do this with\n\n```kotlin\ndependencies {\n    implementation(\"io.cloudflight.platform.spring:platform-spring-caching\")\n    implementation(\"org.springframework.boot:spring-boot-starter-data-redis\")\n    // for sessions\n    implementation(\"org.springframework.session:spring-session-data-redis\")\n}\n```\n\nThe [CachingAutoConfiguration](platform-spring-bom/src/main/kotlin/io/cloudflight/platform/spring/autoconfigure/CachingAutoConfiguration.kt)\nthen registers a CacheErrorHandler that evicts keys when they can't be serialized.\nIt also creates a default RedisCacheConfiguration that supports cache properties like `timeToLive`, `keyPrefix`\nand `isUseKeyPrefix`.\nIt will create a default RedisTemplate with a JSON de/serializer if it cannot find a RedisTemplate.\n\n#### Session Handling\n\nIf you have the `spring-session-core` and `spring-session-data-redis` dependencies on the classpath of\nyour `WebApplication`,\nthe [SessionAutoConfiguration](platform-spring-bom/src/main/kotlin/io/cloudflight/platform/spring/autoconfigure/SessionAutoConfiguration.kt)\nwill automatically configure a RedisSessionRepository for you if you haven't already defined one. In the same manner it\nwill create a SafeRedisSessionSerializer that warns you of non-deserializable sessions.\n\n\u003e **_NOTE:_** The property spring.session.store-type was removed in Spring Boot 3, and so we have removed it as well.\n\u003e The `SessionRepository` is identified by the presence of dependencies on the classpath in the following order:\n\u003e 1. Redis (Our implementation)\n\u003e 2. JDBC (from Spring Boot)\n\u003e 3. Hazelcast (from Spring Boot)\n\u003e 4. Mongo (from Spring Boot)\n\u003e 5. If none of the above are available, no SessionRepository is configured.\n### Scheduling\n\nThe module `platform-spring-scheduling` integrates [Shedlock](https://github.com/lukas-krecan/ShedLock) with Spring-Boot by\nadding `net.javacrumbs.shedlock:shedlock-provider-redis-spring` to the classpath for distributed locking using Redis.\n\nThat means, if you have `platform-spring-scheduling` on the classpath, you can automatically use `@Scheduled` annotations\nalong with the `@SchedulerLock` annotation from Shedlock.\n\nAdditionally, if no `RedisConnection` bean is available, the module automatically creates a `io.cloudflight.platform.spring.scheduling.lock.NoopLockProvider` for you.\nThis way, you can use `@SchedulerLock` also in your tests without the need to have a Redis instance running.\n\n### Internationalization (I18n)\n\nThe module `platform-spring-i18n` provides some additional utility services around Spring's i18n support:\n\n* Tracking available locales\n* Defining a default locale on the server\n\nAdd the module to your server `build.gradle` like that:\n\n````groovy\ndependencies {\n    implementation 'io.cloudflight.platform.spring:platform-spring-i18n'\n}\n````\n\nAdd configuration to your `application.yaml`\n\n````yaml\ncloudflight:\n  i18n:\n    locales:\n      - GERMAN\n    default: GERMAN\n\nspring:\n  messages:\n    basename: classpath:/messages\n````\n\nInject the spring bean `io.cloudflight.platform.i18n.I18nService` to query all available and the default locale on the backend.\n\nImplement the interface `io.cloudflight.platform.i18n.LocaleAccess` in any of your beans to get the the locale of the current thread.\n\nIf you want to handle exposing i18n keys to the frontend in some custom way, use the `ListResourceBundleMessageSource`\nbean directly and disable automatic exposure of all the message-properties via `/api/i18n` with this configuration:\n\n````yaml\ncloudflight:\n  i18n:\n    httpendpoint:\n      enabled: false\n````\n\n### Validation\n\nThe module `platform-spring-validation` gives you client-side support for validating user input, triggered by validations on the server, and it\nplays well together with `platform-spring-i18n`.\n\nForm-validations on client-side are insecure (no-one prevents an arbitrary client to bypass those validations),\nbut on the other hand web clients (like Angular) cannot easily deal with Spring's Backend Validation Support.\n\nThis module builds the bridge between Spring's `BindException` and DTOs which can be serialized as JSON and being used on the client\nto display those validations.\n\nAll you need to do is to embed the module `platform-spring-validation`, the `PlatformValidationAutoConfiguration` will automatically create beans\nto transform all instances of `BindException` or `MethodArgumentNotValidException` to `ErrorResponse` instances which look like the following:\n\n````kotlin\ndata class ErrorResponse(\n    val fieldMessages: List\u003cFieldMessageDto\u003e = emptyList(),\n    val globalMessages: List\u003cGlobalMessageDto\u003e = emptyList()\n)\n````\n\nBehind the scenes, Spring's I18n support around `MessageSource` is being utilized to transform technical error codes into human-readable\nand localized strings. Simply create `messages_[lang].properties` files on the backend\n\nYou can also use Springs JSR303 Validation Support with the according annotations `@Valid`, `@NotNull` and so on, as well as on DTOs\nand on entities.\n\n### Messaging\n\nTBD\n\n## Test modules\n\nThe Cloudflight Platform also provides some modules that help you create Unit or Integration Tests.\n\nAs described in the section dependency management, the platform dependency `platform-spring-test-bom`\nautomatically adds JUnit5, AssertJ and MockK to your `testImplementation` configuration.\n\nWhile those modules are handsome in each module and can be used everywhere, there exist additional test modules within the\nCloudflight platform for more sophisticated tests (mostly for the server modules):\n\n### Performance-Profiling JUnit5 tests\n\nWhen projects get bigger, very often also the test cases get more complex (especially intergration tests) which often\nhas negative impact on the compile/build performance.\n\nIn order to have more transparency of how long your tests, the module `platform-spring-test` adds some profiling support on different levels:\n\n#### Spring Context\n\nFirst thing is that we automatically register a `BufferingApplicationStartup` bean to your test case in order to be able to gain\ninsights of the performance of your `ApplicationContext` when it starts up. Under the hood it uses the same mechanism as described in\n\"Startup time analysis\", that means in order to see the logs, you need to set the logger `io.cloudflight.platform.server.ApplicationStartupPrinter` to `TRACE`\nin your `logback-test.xml`.\n\n### Test-Support for Spring Boot server applications\n\nThis module transitively gives you support to test Spring and Spring Boot applications (`spring-test` and `spring-boot-starter-test`),\nthat means you can automatically use `@SpringBootTest` in your integration tests.\n\nInclude the module `platform-spring-test` as follows in your server module:\n\n````groovy\ndependencies {\n    testImplementation 'io.cloudflight.platform.spring:platform-spring-test'\n}\n````\n\nWARNING: Instances of `@SpringBootTest` are costly during execution. If possible, write plain unit tests in your service modules, and use Spring Boot container tests only in your server modules.\n\n#### Client-side testing of Spring Boot applications\n\nRunning a `@SpringBootTest` is costly, and it should only be used in your Server-Module in order to reduce\ntest execution time. Anyways, you might then also use our support to test your APIs via the network, that means\nstarting up your whole server, dynamically creating a client based on your API interfaces, and then executing\nHTTP requests. That way you are also testing your Spring WebMVC annotations without any mocking infrastructure.\n\nUse the class `FeignTestClientFactory` in connection with `LocalServerPort` as shown in this snippet:\n\n````kotlin\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)     // \u003c1\u003e\nclass FeignTestClientFactoryTest(\n    @Autowired @LocalServerPort private val port: Int                           // \u003c2\u003e\n) {\n\n    private val helloApi =\n        FeignTestClientFactory.createClientApi(HelloWorldApi::class.java, port) // \u003c3\u003e\n\n    @Test\n    fun helloWorld() {\n        assertThat(helloApi.helloWorld(\"John\").name).isEqualTo(\"John\")\n    }\n}\n\n// All subsequent classes usually come from the application itself, you don't need\n// them in your test classes. We just want to give an impression here of what we are\n// testing here\n\n@SpringBootApplication\nclass TestApplication                                                           // \u003c4\u003e\n\n@Api(\"Project\")\ninterface HelloWorldApi {                                                       // \u003c5\u003e\n\n    @GetMapping(\"/hello/world\")\n    fun helloWorld(@RequestParam(\"name\") name: String): HelloWorldDto\n}\n\ndata class HelloWorldDto(val name: String, val time: LocalDateTime)\n\n@RestController\nclass HelloWorldController : HelloWorldApi {                                    // \u003c6\u003e\n    override fun helloWorld(name: String): HelloWorldDto {\n        return HelloWorldDto(name, LocalDateTime.now())\n    }\n}\n````\n\n1. It's important to have `SpringBootTest.WebEnvironment.RANDOM_PORT` here as `webEnvironment`\n2. Inject the `@LocalServerPort` as variable into your test case, it will have the value of of the random port of your server\n3. Create a client using the `FeignTestClientFactory` by passing exactly that port. You may also inject your own `ApplicationContext` here in order to add HTTP interceptors or similar.\n4. Your application classes, usually from your Server-Module\n5. Any API from your -api-module\n6. The server implementation of your API\n\n#### QuickPerf\n\nAdditionally, the module `platform-spring-test` comes with the great library [QuickPerf](https://github.com/quick-perf/doc/wiki/QuickPerf).\nQuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties. The QuickPerf extension\nis being registered by `platform-spring-test`, so you don't need to add `@QuickPerfTest` on your test classes.\n\n\n### Test-Support for JPA\n\nThe module `platform-spring-test-jpa` leverages QuickPerf support by also adding support to [profile SQL queries](https://github.com/quick-perf/doc/wiki/SQL-annotations).\n\nThat way, you can write test methods like that:\n\n````kotlin\n@Test\n@ExpectSelect(1)\nfun getArtifact() {\n    repositoryService.getArtifact(\"foo\", \"bar\")\n}\n````\n\nThis test class will fail if the number of SQL queries being made within the body of that method is not equal to 1.\nHave a look at the [QuickPerf website](https://github.com/quick-perf/doc/wiki/SQL-annotations#Available-SQL-annotations)\nfor all available annotations including configuration support.\n\n### Test-Support for Testcontainers\n\nEmbed the module `platform-spring-test-testcontainers` to get support for [Testcontainers](https://testcontainers.org) via\nthe [the embedded Support of Spring Boot 3.1](https://spring.io/blog/2023/06/23/improved-testcontainers-support-in-spring-boot-3-1).\n\nYou might also have a look at the [latest documentation from Spring Boot on Testcontainers Support](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.testing.testcontainers).\n\n#### MariaDB via Testcontainers\n\nHere is an example how to use the MariaDB testcontainer within your `@SpringBootTest`. First, add the dependency to\n`platform-spring-test-testcontainers` along with `org.testcontainers:mariadb`:\n\n````groovy\ndependencies {\n    testImplementation(\"io.cloudflight.platform.spring:platform-spring-test-testcontainers\")\n    testImplementation(\"org.testcontainers:mariadb\")\n}\n````\n\n\nYour test case then is as easy as to just use the test profile and start a `@SpringBootTest`:\n\n````kotlin\n@SpringBootTest\n@ActiveProfiles(ApplicationContextProfiles.TEST)\n@Testcontainers\nclass ServerIntegrationTest(\n@Autowired private val personService: PersonService\n) {\n\n    companion object {\n        @Container\n        @ServiceConnection\n        val mariaDb = MariaDBContainer(\"mariadb:10.3.6\")\n    }\n\n    @Test\n    fun listPersons() {\n        // your test comes here\n    }\n}\n````\n\nThe underlying libraries have automatically created a MariaDB instance for you in an own container. Use Flyway or Liquibase\nto initialize your database just as in production.\n\n\n### BDD Support\n\nThe module `io.cloudflight.platform.spring:platform-spring-test-bdd` pulls the required libraries of [JGiven](https://jgiven.org) to our classpath. It automatically\nregisters the `JGivenExtension` on all test JUnit5 test cases, so you don't need to add something like `@ExtendsWith(JGivenExtension.class)` to your test cases.\n\nHave a look at the excellent [JGiven documentation](https://jgiven.org/userguide/) how to use the full strength of those tests. This module also ships\na [Kotlin extension for JGiven](https://github.com/toolisticon/jgiven-kotlin) for better JGiven support in Kotlin.\n\n\n### ArchUnit Support\n\nThe module `io.cloudflight.platform.spring:platform-spring-test-archunit` embeds\nthe [ArchUnit CleanCode Verifier](https://github.com/cloudflightio/archunit-cleancode-verifier) and provides\nan `AbstractCleanCodeTest` that you can use as follows:\n\n````kotlin\nimport com.tngtech.archunit.core.importer.ImportOption.DoNotIncludeTests\nimport com.tngtech.archunit.junit.AnalyzeClasses\nimport io.cloudflight.platform.spring.test.archunit.AbstractCleanCodeTest\n\n@AnalyzeClasses(packagesOf = [ArchitectureTest::class], importOptions = [DoNotIncludeTests::class])\nclass ArchitectureTest : AbstractCleanCodeTest() {\n    // your ArchUnit tests go here\n}\n````\n\nIt embeds all `CleanCodeRuleSets` from the [ArchUnit CleanCode Verifier](https://github.com/cloudflightio/archunit-cleancode-verifier). \nHave a look at the documentation in that subproject.\n\nWe recommend to put that test into the root package of the module in your repository which\nimports all other modules (typically a `-server`-module). This way, your whole source code is\nbeing analyzed\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflightio%2Fcloudflight-platform-spring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudflightio%2Fcloudflight-platform-spring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflightio%2Fcloudflight-platform-spring/lists"}