# ADR-035 — `Optional` for three-way PATCH semantics **Status:** Accepted **Date:** 2026-06-08 **Issue:** #751 (JourneyItem CRUD API) ## Context The `PATCH /api/geschichten/{id}/items/{itemId}` endpoint must distinguish three cases for the `note` field: | JSON body | Intended meaning | |-------------------|-----------------------| | `{"note": "text"}`| Set note to "text" | | `{"note": null}` | Clear the note | | `{}` (absent) | Leave note unchanged | The standard library for this on Jackson 2.x is `jackson-databind-nullable` (`JsonNullable` from `org.openapitools`). However, that library targets `com.fasterxml.jackson.*` (Jackson 2.x) and is incompatible with Spring Boot 4.0 / Spring Framework 7, which uses `tools.jackson.*` (Jackson 3.x). The module fails to register and throws at startup. ## Decision Use `Optional` with Java's default field initializer (`= null`) to encode the three states: ```java @Data public class JourneyItemUpdateDTO { private Optional note = null; // Java default — absent = no-op } ``` | Java value | JSON wire | Semantics | |--------------------|-------------------|---------------| | `null` (default) | field absent | no-op | | `Optional.empty()` | `{"note": null}` | clear | | `Optional.of("x")` | `{"note": "x"}` | set | Jackson 3.x natively maps a JSON `null` to `Optional.empty()` and leaves absent fields at their Java default. No custom module is needed. ## Consequences - No external dependency for PATCH semantics — simpler pom.xml. - The DTO field type is `Optional`, not `String` — service code must null-check the field first (`if (noteField == null) return;`) and then call `.orElse(null)` to unwrap. - This pattern applies to any future PATCH DTO that needs three-way semantics on a nullable field. - `jackson-databind-nullable` is removed from `pom.xml`; `JacksonConfig.java` is kept as a placeholder for future custom modules.