Skip to content

Add adapter registry pattern for dependency injection in bounded contexts#45

Merged
vanrogu merged 2 commits intodevelopfrom
claude/refactor-configure-callbacks-bRwvP
Feb 25, 2026
Merged

Add adapter registry pattern for dependency injection in bounded contexts#45
vanrogu merged 2 commits intodevelopfrom
claude/refactor-configure-callbacks-bRwvP

Conversation

@vanrogu
Copy link
Member

@vanrogu vanrogu commented Feb 25, 2026

Summary

This PR introduces a new adapter registry pattern to the bounded context builder, enabling flexible dependency injection and port binding. This replaces the previous pre-configuration callback approach with a more declarative and type-safe mechanism.

Key Changes

  • New AdapterRegistry class: A registry that stores adapter-to-port bindings with optional qualifications, supporting both default and named qualifications for the same port type.

  • New AdapterBinding interface: An intermediate builder step that allows fluent binding of adapters to ports via adapter(instance).forPort(PortType) syntax.

  • Extended BoundedContextBuilder API:

    • adapter(Object) - starts an adapter binding
    • port(Class<T>) - retrieves an adapter for a port type with default qualification
    • port(Class<T>, String) - retrieves an adapter for a port type with named qualification
  • Removed preConfigure callback: Eliminated the FeaturesSpecification.preConfigure() method and its implementation, replacing it with the adapter registry pattern for cleaner separation of concerns.

  • Updated feature slices: Modified benchmark feature slices to use the new adapter pattern instead of pre-configuration callbacks. Adapters are now retrieved directly from the builder during configuration rather than being set up beforehand.

Implementation Details

  • The AdapterRegistry uses a PortKey record to uniquely identify adapter bindings by port type and qualification string.
  • Validation ensures adapters are assignable to their declared port types and prevents duplicate registrations.
  • The adapter binding is integrated into BoundedContextBuilderImpl as an inner class AdapterBindingImpl that delegates to the registry.
  • Feature slices now access shared dependencies (like DataSource and DatabaseInitMode) through the builder's port() methods rather than through pre-configuration.

This change provides a more declarative, type-safe, and testable approach to managing cross-cutting dependencies in bounded contexts.

https://claude.ai/code/session_01L4BtP5BGKBqwTe3rYphCK1

Introduce a declarative port/adapter mechanism for wiring infrastructure
dependencies into feature slices, replacing the preConfigure callback.

API (sliceworkz-eventmodeling-api):
- Add adapter(Object)/port(Class)/port(Class, String) to BoundedContextBuilder
- Add AdapterBinding and QualifiableAdapterBinding for fluent chaining
  with optional .withQualification("name") for named bindings
- Remove preConfigure from FeaturesSpecification

Implementation (sliceworkz-eventmodeling-impl):
- Add AdapterRegistry with register/lookup/requalify operations
- Assignability check: adapter must implement the port type
- Fail-fast: missing port lookup throws IllegalStateException at build time
- Duplicate detection: registering same port+qualification twice throws
- DelegatingBoundedContextBuilder enables QualifiableAdapterBinding to
  continue the builder chain fluently

Benchmark refactoring:
- OrderProcessingFeatureSlice is now a clean marker interface (no preConfigure)
- Feature slices use builder.port(DataSource.class) and
  builder.port(DatabaseInitMode.class) in their configure methods
- BenchmarkApplication uses .adapter(ds).forPort(DataSource.class) and
  .adapter(initMode).forPort(DatabaseInitMode.class)
- Eliminated mutable fields and two-phase initialization from all slices

https://claude.ai/code/session_01L4BtP5BGKBqwTe3rYphCK1
…ectly

Remove QualifiableAdapterBinding and DelegatingBoundedContextBuilder.
Follow the same pattern as FeaturesSpecification.done() and
LiveModelSpecification.live() where the terminal method returns the
builder directly.

AdapterBinding.forPort(Class) now returns BoundedContextBuilder, and an
overload forPort(Class, String) handles qualified bindings. This also
removes the requalify() method from AdapterRegistry since qualification
is now provided upfront.

https://claude.ai/code/session_01L4BtP5BGKBqwTe3rYphCK1
@vanrogu vanrogu merged commit ce4cf96 into develop Feb 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants