From 020953fe476f4834726791732e0e6ab660d38ae3 Mon Sep 17 00:00:00 2001 From: Thomas Vitale Date: Mon, 1 Dec 2025 21:34:50 +0100 Subject: [PATCH] refactor: Review nullability of DoclingDocument * Review nullability of DoclingDocument and related APIs in ConvertDocumentResponse. * Use Docling Serve 1.9.0 as the default image to ensure compatibility covers the latest version. Fixes gh-129 Signed-off-by: Thomas Vitale --- .../ai/docling/api/core/DoclingDocument.java | 139 ++++++++++++++++-- .../response/ConvertDocumentResponse.java | 5 - .../convert/response/DocumentResponse.java | 1 - .../serve/api/convert/response/ErrorItem.java | 5 - .../config/DoclingServeContainerConfig.java | 2 +- docs/src/doc/docs/testcontainers.md | 2 +- 6 files changed, 132 insertions(+), 22 deletions(-) diff --git a/docling-core/src/main/java/ai/docling/api/core/DoclingDocument.java b/docling-core/src/main/java/ai/docling/api/core/DoclingDocument.java index 6e8f9ee..5ba7fe3 100644 --- a/docling-core/src/main/java/ai/docling/api/core/DoclingDocument.java +++ b/docling-core/src/main/java/ai/docling/api/core/DoclingDocument.java @@ -6,9 +6,13 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.Nulls; + +import org.jspecify.annotations.Nullable; /** * Represents a document processed by the Docling service with its structure, @@ -23,29 +27,35 @@ public class DoclingDocument { @JsonProperty("schema_name") + @Nullable private String schemaName; @JsonProperty("version") + @Nullable private String version; @JsonProperty("name") private String name; @JsonProperty("origin") + @Nullable private DocumentOrigin origin; @JsonProperty("body") private GroupItem body; @JsonProperty("groups") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List groups; @JsonProperty("texts") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List texts; @JsonProperty("pictures") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List pictures; @@ -84,6 +94,7 @@ public static class DocumentOrigin { private String filename; @JsonProperty("uri") + @Nullable private String uri; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -124,9 +135,11 @@ public static class GroupItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -134,9 +147,11 @@ public static class GroupItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private BaseMeta meta; @JsonProperty("name") + @Nullable private String name; @JsonProperty("label") @@ -168,6 +183,7 @@ public static class Builder { } @lombok.ToString public static class BaseMeta { @JsonProperty("summary") + @Nullable private SummaryMetaField summary; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -182,9 +198,11 @@ public static class Builder { } @lombok.ToString public static class SummaryMetaField { @JsonProperty("confidence") + @Nullable private Double confidence; @JsonProperty("created_by") + @Nullable private String createdBy; @JsonProperty("text") @@ -248,6 +266,7 @@ public sealed interface BaseTextItem permits TitleItem, SectionHeaderItem, ListI String getSelfRef(); + @Nullable RefItem getParent(); List getChildren(); @@ -262,8 +281,10 @@ public sealed interface BaseTextItem permits TitleItem, SectionHeaderItem, ListI String getText(); + @Nullable Formatting getFormatting(); + @Nullable String getHyperlink(); } @@ -281,16 +302,16 @@ public enum Script { @lombok.ToString public static class Formatting { @JsonProperty("bold") - private Boolean bold; + private boolean bold; @JsonProperty("italic") - private Boolean italic; + private boolean italic; @JsonProperty("underline") - private Boolean underline; + private boolean underline; @JsonProperty("strikethrough") - private Boolean strikethrough; + private boolean strikethrough; @JsonProperty("script") private Script script; @@ -310,9 +331,11 @@ public static final class TitleItem implements BaseTextItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -320,12 +343,14 @@ public static final class TitleItem implements BaseTextItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private BaseMeta meta; @JsonProperty("label") private DocItemLabel label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @@ -336,9 +361,11 @@ public static final class TitleItem implements BaseTextItem { private String text; @JsonProperty("formatting") + @Nullable private Formatting formatting; @JsonProperty("hyperlink") + @Nullable private String hyperlink; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -356,9 +383,11 @@ public static final class SectionHeaderItem implements BaseTextItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -366,12 +395,14 @@ public static final class SectionHeaderItem implements BaseTextItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private BaseMeta meta; @JsonProperty("label") private DocItemLabel label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @@ -382,9 +413,11 @@ public static final class SectionHeaderItem implements BaseTextItem { private String text; @JsonProperty("formatting") + @Nullable private Formatting formatting; @JsonProperty("hyperlink") + @Nullable private String hyperlink; @JsonProperty("level") @@ -405,9 +438,11 @@ public static final class ListItem implements BaseTextItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -415,12 +450,14 @@ public static final class ListItem implements BaseTextItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private BaseMeta meta; @JsonProperty("label") private DocItemLabel label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @@ -431,15 +468,18 @@ public static final class ListItem implements BaseTextItem { private String text; @JsonProperty("formatting") + @Nullable private Formatting formatting; @JsonProperty("hyperlink") + @Nullable private String hyperlink; @JsonProperty("enumerated") - private Boolean enumerated; + private boolean enumerated; @JsonProperty("marker") + @Nullable private String marker; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -457,9 +497,11 @@ public static final class CodeItem implements BaseTextItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -467,12 +509,14 @@ public static final class CodeItem implements BaseTextItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private FloatingMeta meta; @JsonProperty("label") private DocItemLabel label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @@ -483,27 +527,34 @@ public static final class CodeItem implements BaseTextItem { private String text; @JsonProperty("formatting") + @Nullable private Formatting formatting; @JsonProperty("hyperlink") + @Nullable private String hyperlink; @JsonProperty("captions") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List captions; @JsonProperty("references") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List references; @JsonProperty("footnotes") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List footnotes; @JsonProperty("image") + @Nullable private ImageRef image; @JsonProperty("code_language") + @Nullable private String codeLanguage; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -521,9 +572,11 @@ public static final class FormulaItem implements BaseTextItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -531,12 +584,14 @@ public static final class FormulaItem implements BaseTextItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private BaseMeta meta; @JsonProperty("label") private DocItemLabel label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @@ -547,9 +602,11 @@ public static final class FormulaItem implements BaseTextItem { private String text; @JsonProperty("formatting") + @Nullable private Formatting formatting; @JsonProperty("hyperlink") + @Nullable private String hyperlink; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -567,9 +624,11 @@ public static final class TextItem implements BaseTextItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -577,12 +636,14 @@ public static final class TextItem implements BaseTextItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private BaseMeta meta; @JsonProperty("label") private DocItemLabel label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @@ -593,9 +654,11 @@ public static final class TextItem implements BaseTextItem { private String text; @JsonProperty("formatting") + @Nullable private Formatting formatting; @JsonProperty("hyperlink") + @Nullable private String hyperlink; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -610,12 +673,14 @@ public static class Builder { } @lombok.ToString public static class PictureItem { @JsonProperty("self_ref") + @Nullable private String selfRef; @JsonProperty("parent") private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -623,25 +688,31 @@ public static class PictureItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private PictureMeta meta; @JsonProperty("label") private String label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @JsonProperty("captions") + @JsonSetter(nulls = Nulls.AS_EMPTY) private List captions; @JsonProperty("references") + @JsonSetter(nulls = Nulls.AS_EMPTY) private List references; @JsonProperty("footnotes") + @JsonSetter(nulls = Nulls.AS_EMPTY) private List footnotes; @JsonProperty("image") + @Nullable private ImageRef image; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -656,18 +727,23 @@ public static class Builder { } @lombok.ToString public static class PictureMeta { @JsonProperty("summary") + @Nullable private SummaryMetaField summary; @JsonProperty("description") + @Nullable private DescriptionMetaField description; @JsonProperty("classification") + @Nullable private PictureClassificationMetaField classification; @JsonProperty("molecule") + @Nullable private MoleculeMetaField molecule; @JsonProperty("tabular_chart") + @Nullable private TabularChartMetaField tabularChart; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -682,9 +758,11 @@ public static class Builder { } @lombok.ToString public static class DescriptionMetaField { @JsonProperty("confidence") + @Nullable private Double confidence; @JsonProperty("created_by") + @Nullable private String createdBy; @JsonProperty("text") @@ -702,6 +780,7 @@ public static class Builder { } @lombok.ToString public static class PictureClassificationMetaField { @JsonProperty("predictions") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List predictions; @@ -717,9 +796,11 @@ public static class Builder { } @lombok.ToString public static class PictureClassificationPrediction { @JsonProperty("confidence") + @Nullable private Double confidence; @JsonProperty("created_by") + @Nullable private String createdBy; @JsonProperty("class_name") @@ -737,9 +818,11 @@ public static class Builder { } @lombok.ToString public static class MoleculeMetaField { @JsonProperty("confidence") + @Nullable private Double confidence; @JsonProperty("created_by") + @Nullable private String createdBy; @JsonProperty("smi") @@ -757,12 +840,15 @@ public static class Builder { } @lombok.ToString public static class TabularChartMetaField { @JsonProperty("confidence") + @Nullable private Double confidence; @JsonProperty("created_by") + @Nullable private String createdBy; @JsonProperty("title") + @Nullable private String title; @JsonProperty("chart_data") @@ -786,6 +872,7 @@ public static class ProvenanceItem { private BoundingBox bbox; @JsonProperty("charspan") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("charspan") private List charspan; @@ -813,6 +900,7 @@ public static class BoundingBox { private Double b; @JsonProperty("coord_origin") + @Nullable private String coordOrigin; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -870,9 +958,11 @@ public static class TableItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -880,28 +970,34 @@ public static class TableItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private FloatingMeta meta; @JsonProperty("label") private String label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @JsonProperty("captions") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List captions; @JsonProperty("references") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List references; @JsonProperty("footnotes") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List footnotes; @JsonProperty("image") + @Nullable private ImageRef image; @JsonProperty("data") @@ -919,9 +1015,11 @@ public static class Builder { } @lombok.ToString public static class FloatingMeta { @JsonProperty("summary") + @Nullable private SummaryMetaField summary; @JsonProperty("description") + @Nullable private DescriptionMetaField description; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -936,6 +1034,7 @@ public static class Builder { } @lombok.ToString public static class TableData { @JsonProperty("table_cells") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List tableCells; @@ -946,6 +1045,7 @@ public static class TableData { private Integer numCols; @JsonProperty("grid") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("grid") private List> grid; @@ -985,16 +1085,16 @@ public static class TableCell { private String text; @JsonProperty("column_header") - private Boolean columnHeader; + private boolean columnHeader; @JsonProperty("row_header") - private Boolean rowHeader; + private boolean rowHeader; @JsonProperty("row_section") - private Boolean rowSection; + private boolean rowSection; @JsonProperty("fillable") - private Boolean fillable; + private boolean fillable; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") public static class Builder { } @@ -1011,9 +1111,11 @@ public static class KeyValueItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -1021,28 +1123,34 @@ public static class KeyValueItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private FloatingMeta meta; @JsonProperty("label") private String label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @JsonProperty("captions") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List captions; @JsonProperty("references") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List references; @JsonProperty("footnotes") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List footnotes; @JsonProperty("image") + @Nullable private ImageRef image; @JsonProperty("graph") @@ -1060,10 +1168,12 @@ public static class Builder { } @lombok.ToString public static class GraphData { @JsonProperty("cells") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List cells; @JsonProperty("links") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List links; @@ -1098,9 +1208,11 @@ public static class GraphCell { private String orig; @JsonProperty("prov") + @Nullable private ProvenanceItem prov; @JsonProperty("item_ref") + @Nullable private RefItem itemRef; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @@ -1146,9 +1258,11 @@ public static class FormItem { private String selfRef; @JsonProperty("parent") + @Nullable private RefItem parent; @JsonProperty("children") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("child") private List children; @@ -1156,28 +1270,34 @@ public static class FormItem { private ContentLayer contentLayer; @JsonProperty("meta") + @Nullable private FloatingMeta meta; @JsonProperty("label") private String label; @JsonProperty("prov") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular("prov") private List prov; @JsonProperty("captions") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List captions; @JsonProperty("references") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List references; @JsonProperty("footnotes") + @JsonSetter(nulls = Nulls.AS_EMPTY) @lombok.Singular private List footnotes; @JsonProperty("image") + @Nullable private ImageRef image; @JsonProperty("graph") @@ -1198,6 +1318,7 @@ public static class PageItem { private Size size; @JsonProperty("image") + @Nullable private ImageRef image; @JsonProperty("page_no") diff --git a/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ConvertDocumentResponse.java b/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ConvertDocumentResponse.java index d69f7d4..01638d6 100644 --- a/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ConvertDocumentResponse.java +++ b/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ConvertDocumentResponse.java @@ -3,8 +3,6 @@ import java.util.List; import java.util.Map; -import org.jspecify.annotations.Nullable; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; @@ -24,7 +22,6 @@ @lombok.ToString public class ConvertDocumentResponse { @JsonProperty("document") - @Nullable private DocumentResponse document; @JsonProperty("errors") @@ -33,11 +30,9 @@ public class ConvertDocumentResponse { private List errors; @JsonProperty("processing_time") - @Nullable private Double processingTime; @JsonProperty("status") - @Nullable private String status; @JsonProperty("timings") diff --git a/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/DocumentResponse.java b/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/DocumentResponse.java index 714da5c..e999603 100644 --- a/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/DocumentResponse.java +++ b/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/DocumentResponse.java @@ -37,7 +37,6 @@ public class DocumentResponse { private String doctagsContent; @JsonProperty("filename") - @Nullable private String filename; @JsonProperty("html_content") diff --git a/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ErrorItem.java b/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ErrorItem.java index 3ac5449..568c427 100644 --- a/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ErrorItem.java +++ b/docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/convert/response/ErrorItem.java @@ -1,7 +1,5 @@ package ai.docling.serve.api.convert.response; -import org.jspecify.annotations.Nullable; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -19,15 +17,12 @@ @lombok.ToString public class ErrorItem { @JsonProperty("component_type") - @Nullable private String componentType; @JsonProperty("error_message") - @Nullable private String errorMessage; @JsonProperty("module_name") - @Nullable private String moduleName; @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") diff --git a/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/config/DoclingServeContainerConfig.java b/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/config/DoclingServeContainerConfig.java index 7993ba9..b08edf7 100644 --- a/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/config/DoclingServeContainerConfig.java +++ b/docling-testcontainers/src/main/java/ai/docling/testcontainers/serve/config/DoclingServeContainerConfig.java @@ -26,7 +26,7 @@ public interface DoclingServeContainerConfig { /** * Represents the version identifier for the docling-serve container image. */ - String DOCLING_IMAGE_VERSION = "v1.8.0"; + String DOCLING_IMAGE_VERSION = "v1.9.0"; /** * Default image name diff --git a/docs/src/doc/docs/testcontainers.md b/docs/src/doc/docs/testcontainers.md index e0b4803..af0a191 100644 --- a/docs/src/doc/docs/testcontainers.md +++ b/docs/src/doc/docs/testcontainers.md @@ -131,7 +131,7 @@ import ai.docling.testcontainers.serve.DoclingServeContainer; DoclingServeContainerConfig config = DoclingServeContainerConfig.builder() // Override the image if you need a different tag or registry - .image("ghcr.io/docling-project/docling-serve:v1.8.0") + .image("ghcr.io/docling-project/docling-serve:v1.9.0") // Enable the optional web UI served by Docling Serve .enableUi(true) // Pass environment variables to fine‑tune behavior