feat(api)!: replace DoclingServeApiBuilderFactory with DoclingServeApiProvider - #696
Merged
Merged
Conversation
…iProvider DoclingServeApiBuilderFactory handed out a DoclingApiBuilder, an interface every implementation had to implement. Each new configuration option was either a breaking change or a default method throwing UnsupportedOperationException. The new DoclingServeApiProvider SPI instead receives an immutable DoclingServeApiConfig, a final class owned by docling-serve-api, so options can be added without breaking implementations. - DoclingServeApi.builder() returns a DoclingServeApiBuilder collecting a DoclingServeApiConfig; build() hands it to the single available provider - Providers declare the options they don't honor via unsupportedOptions() (IGNORE, WARN or FAIL), enforced only for explicitly set options - DoclingServeApi gains an abstract config(); an API is copied with api.config().toBuilder() - DoclingServeApiBuilderFactory, DoclingApiBuilder and DoclingServeApi.toBuilder() are deprecated for removal. Legacy factories are still used when no provider is found, but options added after the deprecation, such as asyncExecutor, fail through them - docling-serve-client provides DoclingServeClientProvider. The client builder keeps a DoclingServeApiBuilder instead of duplicating every option, and validates values when they are set - DoclingServeClient.builder() detects Jackson 2 or 3 for client-specific settings; the builder() methods of the Jackson clients are now public, and DoclingServeClientBuilderFactory is deprecated for removal - toBuilder() of the reference client keeps the timeouts and the redirect policy - slf4j-api moves from docling-serve-client to docling-serve-api - Remove the unreleased default DoclingApiBuilder.asyncExecutor() from docling-project#691: asyncExecutor is now a DoclingServeApiConfig option - Add a migration guide, and set the release version to 0.7.0 BREAKING CHANGE: DoclingServeApi.builder() now returns a DoclingServeApiBuilder instead of the builder of the implementation, and DoclingServeApi has a new abstract config() method. Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
18 tasks
Contributor
Author
|
Follow-up to remove the deprecated types: #697 |
edeandrea
enabled auto-merge (squash)
September 23, 2026 23:13
:java_duke: JaCoCo coverage report
|
|
||||||||||||||
|
HTML test reports are available as workflow artifacts (zipped HTML). • Download: Artifacts for this run |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
DoclingServeApiBuilderFactoryhanded out aDoclingApiBuilder, an interface that every implementation had to implement. That interface played two roles: the configuration carrier for callers, which must grow, and the extension contract for implementors, which must never change. So each new option was either a breaking change or adefaultmethod throwingUnsupportedOperationException, asasyncExecutorin #691 had to be.This PR splits the two roles. Providers now receive an immutable configuration object owned by
docling-serve-api, so options can be added without breaking implementations.What changes
New SPI (
docling-serve-api)DoclingServeApiProvider:create(DoclingServeApiConfig)returns the API. Discovered withServiceLoader, exactly one provider must be available.DoclingServeApiConfig: a final, immutable class. Every option has a typedConfigOptionconstant and an accessor, and the config records which options were explicitly set.DoclingServeApiBuilder: returned byDoclingServeApi.builder(). It collects a config and hands it to the provider inbuild().unsupportedOptions(): a provider can declare options it doesn't honor asIGNORE,WARNorFAIL. Only options the caller explicitly set are enforced, so declaring an option doesn't affect callers who never touch it.FAILthrows anUnsupportedConfigurationException.DoclingServeApi.config(): new abstract method returning the configuration an API runs with. An API is copied withapi.config().toBuilder().Deprecated for removal, with a fallback
DoclingServeApiBuilderFactory,DoclingServeApi.DoclingApiBuilderandDoclingServeApi.toBuilder().asyncExecutor, makesbuild()fail through a legacy factory instead of being silently dropped.Reference client (
docling-serve-client)DoclingServeClientProvider, registered in place ofDoclingServeClientBuilderFactory.DoclingServeApiBuilderfor the shared options instead of duplicating them as fields, and gainsconfig(DoclingServeApiConfig). The client stores the config and returns it fromconfig().DoclingServeClient.builder(), which detects Jackson 2 or 3, for client-specific settings such ashttpClientBuilder.DoclingServeJackson2Client.builder()andDoclingServeJackson3Client.builder()are now public, forjsonParser. Callers only need to know their Jackson version when writing Jackson code.DoclingServeClientBuilderFactoryis deprecated for removal and delegates toDoclingServeClient.builder().Other changes
defaultDoclingApiBuilder.asyncExecutor()from feat(client): support custom Executor for async operations #691.asyncExecutoris now a config option. It stays@Nullablerather thanOptional, and unset still means the 1-argCompletableFutureoverloads, neverForkJoinPool.commonPool().toBuilder()on the Jackson clients droppedconnectTimeoutandreadTimeout, and the copy stopped following redirects. Proxy, SSL context and authenticator still aren't copied, sinceHttpClientcan't be rebuilt from an instance; this is documented.slf4j-apimoves fromdocling-serve-clienttodocling-serve-api, which now logs theWARNand legacy-factory warnings..github/project.yml.Breaking changes
DoclingServeApi.builder()returns aDoclingServeApiBuilderinstead of the implementation's builder (<T, B> B). Fluent chains andvardeclarations are unaffected; code declaring the builder type must change, and client-specific settings move toDoclingServeClient.builder().DoclingServeApihas a new abstractconfig(). Implementations must add it; binaries compiled against an earlier version throwAbstractMethodErrorif it's called.connectTimeout(Duration.ZERO)now throws from the setter instead of frombuild().config()on the reference client reports only the options that were explicitly set, and the base URL as given.Documentation
docling-serve/serve-api-provider-migration.md, in the nav: before/after examples for the provider, service registration,unsupportedOptions(),config(), callers of the builder, and tests to check the migration. Every Java snippet on the page was compiled.serve-api.md,serve-client.md,whats-new.mdandCLAUDE.mdupdated.Testing
docling-serve-api: 237 tests pass. New tests cover the config, the builder,unsupportedOptions()enforcement, provider resolution (new, legacy, both, none, several) and the legacy adapter. Guard tests fail if aConfigOptionconstant, its accessor and its builder setter get out of sync.docling-serve-client: the provider, builder, deprecated-factory, config and async-executor suites pass for both Jackson 2 and Jackson 3 (38 tests). A guard test fails if a shared setter is missing from the client builder.:docling-native-tests:nativeClientTestpasses with GraalVM 25 for Jackson 2 and Jackson 3.docling-serve-clientsuite, which needs Docker (Testcontainers). I'm relying on CI for it.Follow-up
A separate issue will track removing the deprecated types once third-party implementations have migrated.