Skip to content

DOC-6829 Add preemptive Spring Data Redis JSON docs [PARKED] - #3611

Open
andy-stark-redis wants to merge 2 commits into
mainfrom
DOC-6829-preemptive-spring-data-redis-json-docs
Open

DOC-6829 Add preemptive Spring Data Redis JSON docs [PARKED]#3611
andy-stark-redis wants to merge 2 commits into
mainfrom
DOC-6829-preemptive-spring-data-redis-json-docs

Conversation

@andy-stark-redis

@andy-stark-redis andy-stark-redis commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Preemptively documents the new template-layer JSON API in Spring Data Redis (DOC-6829), ahead of its upstream release. Adds a new recipe page under the Spring Data Redis section and links it from the section index.

  • New page: content/integrate/spring-framework-cache/json.md
  • Index entry: content/integrate/spring-framework-cache/_index.md

Warning

This PR is parked — do not merge. The docs are written against an unreleased, still-under-review upstream PR (spring-data-redis#3390). Merge only after the feature ships and the manifest below has been reconciled (see /unpark).

Park manifest

Ticket: DOC-6829
Parked at: 2026-07-10
Trigger to pick up: the JSON API is present in a released spring-data-redis version — testably, gh api "repos/spring-projects/spring-data-redis/contents/src/main/java/org/springframework/data/redis/core/RedisJsonTemplate.java?ref=<tag>" returns 200 at a release tag newer than 4.1.0. The expected first such release is 4.2.0-M1. ✅ FIRED 2026-08-214.2.0-M1 shipped and contains the API (see the 2026-08-25 update below). The remaining blocker is no longer upstream at all: it was the milestone-vs-GA decision in the checklist below — DECIDED 2026-08-26: hold for 4.2.0 GA. New trigger: a non-prerelease 4.2.0 tag containing core/RedisJsonTemplate.java. The page is now API-correct against 4.2.0-M1 and stays parked purely for the GA gate.
Labels: parked, do not merge yet

Pinned sources (state observed at park time)

Source URL Snapshot at park
SDR JSON support PR spring-projects/spring-data-redis#3390 state: open, merged: false, head SHA e35714beca1c1ac46f0cb8a325ac95b9e6199d0f, base main, milestone: none (no target version), updated 2026-07-08

To diff on unpark: re-read JsonOperations.java and RedisJsonTemplate.java at the released tag. Do not gate on the PR's merged flag — see the correction below.

⚠️ Trigger test CORRECTED — 2026-08-13 (/pr-scan-review)

The original trigger test could never fire. It said to compare merged / head.sha against the
snapshot. Spring Data projects rebase and close rather than merging, so #3390 reads
state: closed, merged: false, merged_at: null permanently, and its head SHA
(a7239457, moved from the park-time e35714be) never becomes a merge commit. A future /unpark 3611
following the manifest literally would have concluded "still open, hold" — and been wrong.

The code is on main and has been since before this scan. Verified three ways, not inferred from the
PR state:

Check Result @ 2026-08-13
main commit 8927add1 "Add support for Redis JSON" (also cf7878ec "Polishing" 2026-08-12)
core/RedisJsonTemplate.java @ main blob 0d79685d2e77eaaa40d08db41196954324e30e18, 23849 bytes
core/JsonOperations.java @ main blob b15772310a9cecccf4d193d52c213e135fe9019f, 22416 bytes
#3390 milestone 4.2.0-M1 (2026.1.0) (was none at park time)
main HEAD bc6fa4ab "Enter rampdown phase for 4.2.0-M1." (2026-08-13) — the M1 release is imminent
Latest releases 4.1.0 (2026-06-09), 3.5.13 (2026-06-24) → no released version contains JSON yet

So the blocker is now only the release, not the merge. Also on main: the 3.x→4.x migration guide
(#3403, commit 4d7f8038) — likewise closed, merged: false. Checked: this repo has no Redis-side SDR
migration docs (only content/integrate/spring-framework-cache/{_index,cache,geo-failover}.md), so there is
nothing to align with it. Don't re-derive that at unpark.

Re-fetch: gh api "repos/spring-projects/spring-data-redis/contents/src/main/java/org/springframework/data/redis/core/RedisJsonTemplate.java?ref=<tag>" --jq '{sha,size}' and
gh api repos/spring-projects/spring-data-redis/releases --jq '.[0:5][] | {tag:.tag_name,published:.published_at}'

✅ Trigger FIRED — 2026-08-21, verified 2026-08-25 (/pr-scan-review)

4.2.0-M1 was released on 2026-08-21 and contains the JSON API. The 2026-08-13 row saying "no
released version contains JSON yet" is now stale. Supersedes it:

Check Result @ 2026-08-25
4.2.0-M1 (2026-08-21, prerelease: true) contains RedisJsonTemplate.java and JsonOperations.java
4.1.1 (2026-08-21, GA) RedisJsonTemplate.javaHTTP 404 — no JSON API
4.0.7 (2026-08-21, GA) RedisJsonTemplate.javaHTTP 404 — no JSON API
Newest GA on the 4.2 line none yet4.2.0 GA has not shipped

Signature check is DISCHARGED — do not redo it. Both blobs are byte-identical at the 4.2.0-M1
tag to the 2026-08-13 main snapshot:

File @ 4.2.0-M1 Blob Size vs main 08-13
core/RedisJsonTemplate.java 0d79685d 23849 unchanged
core/JsonOperations.java b1577231 22416 unchanged

Per the checklist rule "if those are unchanged at the tag, no signature can have moved": no signature
moved.
The four confirmed defects in the 2026-08-13 reconciliation note are therefore still exactly
the work required — no more, and nothing new has drifted underneath them.

What this leaves. Upstream is no longer the blocker; the open question is entirely ours, and it is
the checklist's "Version" item: is a milestone build enough to publish against? Note both GA releases
cut on the same day (2026-08-21) deliberately omit the API, so "wait for GA" means waiting for 4.2.0
proper, not for a patch on 4.1.x/4.0.x.

🔴 Signature reconciliation — four CONFIRMED defects, 2026-08-13 (/pr-scan-review)

Because the API is now on main at fixed blob SHAs, the "LOW confidence" section below stopped being
speculative and became checkable — so it was checked. Four of the page's claims are wrong and one
snippet would not compile. Each was verified by reading the files/directory listings at main, not by code
search alone (search total_count: 0 is not evidence on its own).

Page claims Reality @ main
new JacksonRedisJsonSerializer<>(User.class) No such class. The interface is RedisJsonSerializer extends RedisSerializer<Object>; the Jackson impls in serializer/ are JacksonJsonRedisSerializer, GenericJacksonJsonRedisSerializer (plus the Jackson2 pair)
"Use StringRedisJsonTemplate if you want String keys…" No such class. core/ contains only JsonOperations.java, RedisJsonOperations.java, RedisJsonTemplate.java
RedisJsonTemplate<String, User> + no-arg new + setKeySerializer() / setJsonSerializer() public class RedisJsonTemplate<K> implements RedisJsonOperations<K>one type parameter, constructor-injected: RedisJsonTemplate(RedisConnectionFactory, RedisSerializer<K> keySerializer, …). No matching setters
JsonResult<User> / JsonResult<String> interface JsonResult extends JsonValuenot generic. Values come out via as(Class) / asString(). Note a separate JsonResults extends Streamable<JsonResult> exists for the multi-key form

Resolved cleanly in the page's favour — do not re-check these:

  • mergeWith(Object) kept its name (checklist item "may ship as merge" → resolved, it did not).
  • setIfAbsent exists (a default delegating to conditional(JsonSetSpec::ifAbsent).set(value)); setIfPresent also exists and the page does not yet mention it.
  • The get(K key) vs fluent value(key).get() disagreement was both readings being right: get(K) is a default method delegating to value(key).get(). Same for paths(key, String...) (on JsonOperations) vs path(String) (on PathSpec) — both exist.
  • array().length(), array().trim(int,int), array().indexOf(Object), string().length()List<@Nullable Long>; bool().toggle()List<@Nullable Boolean>. All match the page exactly.
  • opsForJson() was NOT added — absent from both RedisOperations and RedisTemplate. The checklist item "if added before release, lead the page with it" resolves as no restructure needed; RedisJsonTemplate stays the entry point.

The damage is therefore confined to the bean-wiring block and the result types — the fluent operation
surface the page spends most of its length on is correct.

🟢 Reconciled against released 4.2.0-M1 — 2026-08-26 (/unpark 3611)

The page is now API-correct. Commit 363dd624. Decision taken: hold for 4.2.0 GA, because 4.2.0-M1
is a milestone and Spring does not freeze API at M1. Labels stay on; bannerText stays (rewritten — it still
described #3390 as an in-progress PR).

Re-pinned first, not trusted: both blobs are still 0d79685d/23849 and b1577231/22416 at 4.2.0-M1,
and no release has shipped since 2026-08-21. So the 08-25 signature discharge holds.

⚠️ Two corrections TO THIS MANIFEST. The notes above were not fully reliable:

  1. The bean-wiring fix prescribed above would not have compiled. It listed JacksonJsonRedisSerializer
    and GenericJacksonJsonRedisSerializer as the replacements for the non-existent JacksonRedisJsonSerializer.
    Only the Generic* pair implements RedisJsonSerializer, which is what the constructor demands:

    Class @ 4.2.0-M1 Implements Usable as 3rd ctor arg
    JacksonJsonRedisSerializer<T> RedisSerializer<T> no
    Jackson2JsonRedisSerializer<T> RedisSerializer<T> no
    GenericJacksonJsonRedisSerializer RedisJsonSerializer yes (Jackson 3)
    GenericJackson2JsonRedisSerializer RedisJsonSerializer yes (Jackson 2)

    Neither Generic* class has a no-arg constructor — use builder().build(), create(…), or (ObjectMapper).
    The blob-identity discharge could never have caught this: these classes live in files this manifest never
    pinned.
    A discharge is only as wide as its pins.

  2. "The fluent surface is correct as written" was wrong. Two of the six defects were in that surface:

    • result.getValue() does not exist on JsonResult (as(Class) / as(ParameterizedTypeReference) /
      asString() / map() / isNull()). Not in the 08-13 four-defect table.
    • value(key).paths(…) exists on nothing. paths is top-level on JsonOperations; the specs carry only
      path(String) via PathSpec. The 08-13 note said "both paths(key,…) and path(String) exist" — true, but
      it masked that the page used a third form belonging to neither.

    A signature diff proves nothing moved. It does not prove the page ever matched.

Verified correct, do not re-check: array() (append/length/trim/indexOfList<@Nullable Long>),
string() (append/length), bool().toggle()List<@Nullable Boolean>, mergeWith(Object), set,
setIfAbsent, setIfPresent, value().get(), path(), RedisSerializer.string().
Jedis/Lettuce parity CONFIRMED at the tag — both ship *JsonCommands and *ClusterJsonCommands.
All 7 relref targets resolve.

Observed API shape the page assumes (LOW confidence at park time — superseded by the 2026-08-13 reconciliation note above)

  • Fluent, spec-based entry points on RedisJsonTemplate: value(key), array(key), string(key), bool(key).
  • .path("$.jsonpath") chaining; set / setIfAbsent / get / paths.
  • Array: append, length, indexOf, trim. String: append, length. Boolean: toggle. Document: mergeWith.
  • Bean wiring: RedisJsonTemplate + JacksonRedisJsonSerializer(Type.class) over the existing RedisConnectionFactory.
  • Access is client-agnostic: identical API over Jedis and Lettuce (clients diverge only in internal converters/path types; full parity in the PR).

Re-check checklist (work these on unpark)

  • (highest risk) Rewrite the bean-wiring block — DONE 2026-08-26 (363dd624). Now RedisJsonTemplate<String> (one type param) built via the 3-arg constructor with GenericJacksonJsonRedisSerializer.builder().build(). Read correction 1 in the 08-26 note before touching this — the fix originally prescribed here would not have compiled. Original text: RedisJsonTemplate<K> is single-parameter and constructor-injected, and both JacksonRedisJsonSerializer and StringRedisJsonTemplate do not exist. The snippet as written will not compile. See the 2026-08-13 reconciliation table.
  • Fix the result types — DONE 2026-08-26 (363dd624). JsonResult de-genericised; getValue() (which does not exist) replaced with as(User.class); value(key).paths(…) replaced with the top-level paths(key, …) + asString(). Original text: JsonResult is not generic; replace JsonResult<User> / JsonResult<String> with JsonResult + as(Class) / asString().
  • Method signatures — DONE 2026-08-25. Diffed at the released 4.2.0-M1 tag: both blobs are byte-identical to the 2026-08-13 main snapshot (0d79685d/23849, b1577231/22416), so by this item's own rule no signature can have moved. Re-open only if unparking against a different tag than 4.2.0-M1. ⚠️ This item also claimed "the fluent surface is correct as written" — that was WRONG, corrected 2026-08-26: getValue() and value(key).paths(…) were both bogus. A signature diff proves nothing moved; it does not prove the page ever matched.
  • opsForJson() — DONE 2026-08-25. Re-checked at the released 4.2.0-M1 tag: absent from both RedisOperations.java and RedisTemplate.java (0 occurrences each, against a positive control of opsForHash = 1, so this is a real absence and not a broken check). RedisJsonTemplate stays the entry point; no page restructure needed. Item closed — do not re-derive.
  • (SOLE REMAINING BLOCKER) Version — decision taken 2026-08-26: hold for 4.2.0 GA. The {version} placeholder stays until a non-prerelease 4.2.0 ships; then replace it and re-diff both blobs at that tag. Rationale: M1 is not API-frozen, and the same-day GA releases (4.1.1, 4.0.7) deliberately omit the API, so there is no GA option short of 4.2.0. Original text: replace the {version} placeholder in the Maven/Gradle snippets with the first release that includes JSON support. As of 2026-08-25 that is 4.2.0-M1, a milestone/pre-release; the GA releases cut the same day (4.1.1, 4.0.7) deliberately omit the API, so there is no GA option short of 4.2.0 itself. Decide explicitly whether a milestone build is enough to publish against — if yes, the page must say the API is milestone-only and name the milestone repository; if no, hold for 4.2.0 GA and re-run the blob diff at that tag.
  • BoundJsonOperations — DID NOT LAND, closed 2026-08-26. Absent from core/ at 4.2.0-M1 (directory listing shows only JsonOperations, RedisJsonOperations, RedisJsonTemplate; code search 0 hits). No bound-operations section needed. Do not re-derive. Original text: explicitly deferred in the PR. If it lands before GA, add a bound-operations section.
  • setIfPresent — DONE 2026-08-26. Now covered on the page alongside setIfAbsent. Original text: exists on main and the page doesn't mention it. Decide whether to cover it alongside setIfAbsent.
  • Runnable examples — convert inline java blocks to tested TCE (clients-example) doctests once the feature reaches the client example repos.
  • Jedis/Lettuce parity — CONFIRMED 2026-08-26 at the 4.2.0-M1 tag: both jedis/ and lettuce/ ship *JsonCommands and *ClusterJsonCommands. Re-confirm at the GA tag. Original text: re-confirm the "works with either" claim; the two clients could ship support on different timelines.
  • Staleness — rebase/merge main; re-run link checks. Partially done 2026-08-26: all 7 relref targets re-verified as resolving, and bannerText was rewritten (it still described DEV/RI: document new search workspace #3390 as in-progress). The branch has not been rebased onto main — deliberately deferred, to keep this parked branch free of merge noise until the GA unpark.

On unpark, then

Update the docs to reconcile, remove the bannerText warning, drop the parked / do not merge yet labels, run /reflect (record what actually changed vs predicted) and /finalize (the durable squash — deferred until now on purpose so these re-check notes survive).

🤖 Generated with Claude Code


Note

Low Risk
Documentation-only changes with no runtime or security impact; publishing still depends on the milestone-vs-GA version decision noted in the PR.

Overview
Adds documentation for Spring Data Redis’s template-based JSON API (DOC-6829): a new recipe under Spring Data Redis and a bullet on the section index linking to it.

The json.md page covers requirements (Redis JSON, Lettuce/Jedis, Jackson), Maven/Gradle setup with a {version} placeholder, RedisJsonTemplate bean wiring, and fluent examples for whole-document value() ops, JSON path updates (setIfAbsent / setIfPresent), array() / string() / bool() helpers, and mergeWith(). It includes a bannerText warning that JSON support is only in the 4.2.0-M1 milestone until GA, plus relatedPages to Redis JSON and client docs.

Reviewed by Cursor Bugbot for commit 363dd62. Bugbot is set up for automated code reviews on this repo. Configure here.

Document the new template-layer JSON API from the in-progress SDR PR
spring-projects/spring-data-redis#3390 ahead of its release. The page
lives under content/integrate/spring-framework-cache/, which despite the
directory name is the Spring Data Redis section (LinkTitle "Spring Data
Redis"), alongside the cache and geo-failover recipes.

The non-obvious call: no per-client split. RedisJsonTemplate/JsonOperations
is client-agnostic and identical whether Jedis or Lettuce backs the
connection — the clients diverge only in internal converters/path types
below the API surface, with full feature parity. So one set of examples
serves both. Examples are inline java (not runnable TCE snippets) because
the feature isn't in the client example repos yet, and a bannerText flags
the API as unreleased and subject to change.

Learned: SDR JSON template API is unified across Jedis/Lettuce; docs based on an unmerged PR
Directive: keep the JSON examples client-agnostic — do not split into Jedis vs Lettuce variants
Recheck: when spring-data-redis#3390 merges and ships — re-verify method signatures, bean/serializer wiring, and convert examples to runnable TCE doctests
Gaps: code examples untested; signatures and API shape read from an in-progress, still-reviewed diff
Ticket: DOC-6829
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@andy-stark-redis andy-stark-redis added do not merge yet parked PR speculatively added based on pre-release info. Check validity when release goes ahead. labels Jul 10, 2026
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

DOC-6829

andy-stark-redis added a commit that referenced this pull request Jul 22, 2026
Renamed the parked-PR thaw skill from `/pickup` to `/unpark` — directory, frontmatter, title, and prose — to free the `/pickup` name for another skill where it fits better; `park`/`unpark` also reads as a cleaner verb pair. Updated the two files that reference it, `/park` and the shared `_shared/park-manifest.md` contract, so the pairing stays consistent. The three parked PRs that instructed `/pickup <n>` (#3611, #3641, #3652) were updated out-of-band so no stale invocation survives. Approved by dwdougherty; Cursor Bugbot clean.

Directive: Two "pickup" strings are left un-renamed on purpose — the historical .claude/state/assess-comments.coverage.md audit log (it records the skill's old name as it was at the time; renaming falsifies history) and the "Trigger to pick up:" manifest field name in park-manifest.md (a header field, not the skill name). Don't "fix" them in a follow-up grep-and-replace.
Ticket: DOC-6876
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The API this page was written against shipped in spring-data-redis 4.2.0-M1
(2026-08-21). Reconciling the page against the released source fixed six
defects, four of them compile errors. Still parked: 4.2.0-M1 is a milestone,
not a GA release, so the API can still move before 4.2.0.

Fixed:

- Bean wiring. `RedisJsonTemplate<K>` has ONE type parameter (the key type)
  and is constructor-injected, not a no-arg bean with setters. The page's
  `RedisJsonTemplate<String, User>` + `setJsonSerializer()` form does not
  exist in any released version.
- `JacksonRedisJsonSerializer` and `StringRedisJsonTemplate` do not exist.
- `JsonResult` is not generic, and `getValue()` is not one of its methods.
  Values come out via `as(Class)` / `asString()` / `map()`.
- `value(key).paths(...)` exists on nothing. `paths` is a top-level
  `JsonOperations` method; the specs only carry `path(String)`.
- Added `setIfPresent`, which exists as a default alongside `setIfAbsent`.
- Banner rewritten: it still described #3390 as an in-progress PR.

The most useful thing this taught: the park manifest's own correction note
was itself wrong, and following it would have produced a second compile
error. It offered `JacksonJsonRedisSerializer` and
`GenericJacksonJsonRedisSerializer` as interchangeable replacements. They
are not. `JacksonJsonRedisSerializer<T> implements RedisSerializer<T>`,
while the constructor demands `RedisJsonSerializer` — only the two
`Generic*` classes implement it. Identical-looking names, incompatible
types, and the byte-identical blob check that discharged the "signatures"
item could never have caught it, because these classes live in files the
manifest never pinned. A discharge is only as wide as its pins.

Second lesson: the manifest declared the fluent surface "correct as
written" after a signature diff. Two of the six defects were in that
surface. A signature diff proves nothing moved; it does not prove the page
ever matched.

Learned: a park manifest's correction notes need the same scepticism as the page they correct; a blob-identity discharge only covers the files it pins
Ticket: DOC-6829
Constraint: RedisJsonTemplate's 3rd ctor arg must implement RedisJsonSerializer — only GenericJacksonJsonRedisSerializer (Jackson 3) and GenericJackson2JsonRedisSerializer (Jackson 2) do.
Rejected: JacksonJsonRedisSerializer as the document serializer | implements RedisSerializer<T>, not RedisJsonSerializer; will not compile
Recheck: when spring-data-redis 4.2.0 reaches GA — re-diff both blobs at the GA tag and replace the {version} placeholder
Gaps: no snippet was compiled against the 4.2.0-M1 artifact; every signature was read from source at the tag, which is weaker than a build
Directive: BoundJsonOperations is absent at 4.2.0-M1 (0 hits, core/ listing confirms) — do not re-derive that check
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

🧠 Redis Memory

Found 5 related items from repository history (5 new this commit):

Memory updated at 363dd62

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge yet parked PR speculatively added based on pre-release info. Check validity when release goes ahead.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant