Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public sealed abstract class ChunkDocumentRequest extends DocumentRequest
@JsonProperty("include_converted_doc")
private boolean includeConvertedDoc;

@Override
public abstract ChunkDocumentRequest.Builder<?, ?> toBuilder();

@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
public abstract static class ChunkDocumentRequestBuilder<C extends ChunkDocumentRequest, B extends ChunkDocumentRequestBuilder<C, B>> extends DocumentRequest.DocumentRequestBuilder<C, B> {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
* case HybridChunkDocumentRequest r -> client.chunkSourceWithHybridChunker(r);
* }
* }</pre>
*
* <p>Because {@link #toBuilder()} is available on the base type, a source (or target) can be
* injected once — polymorphically — before dispatching, without needing to know the concrete type:
*
* <pre>{@code
* DocumentRequest withSource = request.toBuilder().source(source).build();
* }</pre>
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@tools.jackson.databind.annotation.JsonDeserialize(builder = DocumentRequest.DocumentRequestBuilder.class)
Expand Down Expand Up @@ -63,6 +70,14 @@ public abstract sealed class DocumentRequest
@Nullable
private Target target;

/**
* Returns a builder pre-populated with this request's current field values, allowing a modified
* copy to be created. Each concrete subtype returns its own builder covariantly.
*
* @return a builder initialized from this request
*/
public abstract DocumentRequest.Builder<?, ?> toBuilder();

@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
public abstract static class DocumentRequestBuilder<C extends DocumentRequest, B extends DocumentRequestBuilder<C, B>> {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,44 @@ void toBuilderPreservesSourcesAndTarget() {
assertThat(copy.getTarget()).isSameAs(original.getTarget());
}

@Test
void toBuilderReachableThroughBaseType() {
var target = InBodyTarget.builder().build();

DocumentRequest original = ConvertDocumentRequest.builder()
.target(target)
.build();

DocumentRequest withSource = original.toBuilder()
.source(HTTP_SOURCE)
.build();

assertThat(withSource.getSources())
.singleElement()
.isEqualTo(HTTP_SOURCE);

assertThat(withSource.getTarget()).isSameAs(target);
}

@Test
void toBuilderThroughBaseTypePreservesConcreteType() {
List<DocumentRequest> requests = List.of(
ConvertDocumentRequest.builder().source(HTTP_SOURCE).build(), BatchConvertDocumentRequest.builder().source(HTTP_SOURCE).target(ZipTarget.builder().build())
.build(), HierarchicalChunkDocumentRequest.builder().source(HTTP_SOURCE).build(), HybridChunkDocumentRequest.builder().source(HTTP_SOURCE).build()
);

var rebuiltClasses = requests.stream()
.map(request -> request.toBuilder().build())
.map(Object::getClass)
.toList();

var originalClasses = requests.stream()
.map(Object::getClass)
.toList();

assertThat(rebuiltClasses).isEqualTo(originalClasses);
}

@Test
void batchConvertGetTargetThrowsWhenTargetIsNull() {
BatchConvertDocumentRequest request = BatchConvertDocumentRequest.builder()
Expand Down
1 change: 1 addition & 0 deletions docs/src/doc/docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Docling Java {{ gradle.project_version }} includes important breaking changes, a

* **New `DocumentRequest` sealed base class** — `ConvertDocumentRequest`, `BatchConvertDocumentRequest`, and `ChunkDocumentRequest` now extend a common `DocumentRequest` abstract class in the `ai.docling.serve.api.request` package. This enables polymorphism when working with different request types — for example, accepting a `DocumentRequest` and dispatching to the correct endpoint based on the concrete type via pattern matching.
* **New `ProcessedDocumentResponse` sealed base class** — `ConvertDocumentResponse` and `ChunkDocumentResponse` now extend a common `ProcessedDocumentResponse` abstract class in the `ai.docling.serve.api.response` package. This enables polymorphic handling of document processing responses — for example, using `ProcessedDocumentResponse` as a type bound in generic APIs that work with both conversion and chunking results.
* **`toBuilder()` on the `DocumentRequest` base type** — `DocumentRequest` (and the intermediate `ChunkDocumentRequest`) now expose `toBuilder()`, so a request can be cloned and modified through the base type without first pattern-matching on the concrete subtype. This makes it possible to inject a `source` or `target` once — polymorphically — before dispatching, e.g. `request.toBuilder().source(source).build()`.

### 0.6.1

Expand Down
Loading