Skip to content

feat: Add a Spring Boot starter that creates the client from the configuration of the application. - #14

Merged
goloroden merged 3 commits into
mainfrom
spring-boot-starter
Oct 8, 2026
Merged

goloroden merged 3 commits into
mainfrom
spring-boot-starter

Conversation

@goloroden

@goloroden goloroden commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Adds a third artifact, io.thenativeweb:eventsourcingdb-spring-boot-starter, that sets up the client in Spring Boot 4 applications.

It builds on #13, which made the test container a Testcontainers GenericContainer, so that @ServiceConnection can use it.

What the starter does

  • Client from the configuration: It creates a Client bean from eventsourcingdb.base-url and eventsourcingdb.api-token. If one of them is not set (or empty), the application fails to start with eventsourcingdb.base-url must be set or eventsourcingdb.api-token must be set. There is no default URL.
  • Data mapper: If the application has a Spring JsonMapper, the client uses it for the data of events, so the data follows the Jackson configuration of the application. Otherwise it uses a mapper of its own.
  • Customizing: An application that defines its own Client bean gets that one instead. It can inject EventSourcingDbConnectionDetails to connect its client to the configured instance.
  • Closing: Spring closes the client when the context shuts down.
  • @ServiceConnection: A test container bean annotated with @ServiceConnection provides the URL and the API token, so tests need no properties.

Public types live in io.thenativeweb.eventsourcingdb.springboot: EventSourcingDbAutoConfiguration, EventSourcingDbConnectionDetails (getBaseUrl(), getApiToken()) and EventSourcingDbProperties. The factory for @ServiceConnection is package-private, as in Spring Boot itself.

Dependencies

The starter brings spring-boot-starter (as Spring requires of starters) and the client. It does not bring the test container or spring-boot-testcontainers (compileOnly). Applications add both to their tests anyway, to create the container.

The @ServiceConnection factory is registered in spring.factories, the way Spring's own modules (e.g. spring-boot-data-redis) register theirs:

  • Without spring-boot-testcontainers: Spring Boot can not load the factory and skips it.
  • Without our test container module: The factory skips itself, since it names the container class as a required class. Without that, it would carry on matching containers despite the missing class. This was checked once by hand, on a classpath without the module.

Built against Spring Boot 4.1.1. The tests also pass against Spring Boot 4.0.8, so the README says "Spring Boot 4". Which Jackson versions the client supports is still an open question before publishing: Spring Boot pins Jackson to 3.1.x, while we build against 3.2.3.

Build

  • Configuration metadata: The configuration processor generates spring-configuration-metadata.json, so IDEs complete and explain the two properties. It reads @ConfigurationProperties without claiming it. javac warns about that in the lint category processing, and -Werror turns the warning into an error. As agreed, only that category is turned off, only for the main code of the starter. All other warnings stay errors.
  • Logging in tests: The tests of the starter exclude slf4j-nop, because Spring Boot refuses to start next to it while Logback is present. A logback-test.xml keeps the output quiet instead.
  • AssertJ: It is a test-only dependency, since the test support of Spring Boot builds on it.

Tests

make qa passes (191 + 13 + 10 tests, 100% coverage in all three modules):

  • ApplicationContextRunner tests: These run against a real container. They cover the properties, connection details of the application, an application-defined client, Spring's JsonMapper versus the client's own mapper, closing with the context, and missing properties.
  • @SpringBootTest: It wires the container through @ServiceConnection, exactly as the README describes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Hc2MPSLu7HDHTm8HiBsrDz

goloroden and others added 2 commits October 8, 2026 17:36
…hand out a client with options.

Container wrapped a GenericContainer, so it did not work where
frameworks expect a Testcontainers container, e.g. with @Serviceconnection
in Spring Boot. It now extends GenericContainer, as the official modules
of Testcontainers do. All of its methods keep their names and their
behavior, including replacing a container whose database does not
become reachable. It also works in a try-with-resources statement now.

getClient(ClientOptions) hands out a client with options of the caller,
so that tests can use the same data mapper as production.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hc2MPSLu7HDHTm8HiBsrDz
…iguration of the application.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hc2MPSLu7HDHTm8HiBsrDz
@goloroden
goloroden requested a review from a team as a code owner October 8, 2026 17:29
@goloroden goloroden self-assigned this Oct 8, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hc2MPSLu7HDHTm8HiBsrDz
@goloroden
goloroden merged commit 382b29d into main Oct 8, 2026
3 checks passed
@goloroden
goloroden deleted the spring-boot-starter branch October 8, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant