Skip to content

OXY-147: add JsonEncoder.Omit typeclass and @jsonOmit annotation - #297

Open
Kalin-Rudnicki wants to merge 1 commit into
mainfrom
OXY-147
Open

OXY-147: add JsonEncoder.Omit typeclass and @jsonOmit annotation#297
Kalin-Rudnicki wants to merge 1 commit into
mainfrom
OXY-147

Conversation

@Kalin-Rudnicki

Copy link
Copy Markdown
Owner

What

Adds a first-class "omit from JSON" capability to oxygen-json, mirroring the existing jsonSecret/SecretValue/JsonEncoder.Secret pattern but for unconditional suppression (a field that never appears on the wire) rather than redaction.

Two mechanisms:

  • @jsonOmit annotation — omit a plain field without changing its type.
  • OmitValue[A] opaque wrapper — the type carries omit semantics.

Changes

  • annotations.scala: @jsonOmit.
  • JsonEncoder.scala: def omit + Omit/OmitEncoder (addToObject = false); handle @jsonOmit in productDeriver.
  • OmitValue.scala: new opaque wrapper with encoder + decoder givens.
  • DeriveProductJsonEncoder.scala: emit Growable.empty for @jsonOmit fields in both object-field paths (wins over @jsonFlatten).
  • DeriveProductJsonDecoder.scala: omitted key dropped from keys; field reconstructed from onMissingFromObject/default.
  • JsonSchema.scala: hide @jsonOmit fields from the emitted schema.
  • predef/json.scala: export jsonOmit + OmitValue.
  • Tests: JsonSpec omit suite + JsonSchemaEmitterSpec omit-hidden test.

Key decision (needs a look)

Decode-when-key-is-present differs by mechanism:

  • @jsonOmit: fully transient — incoming value ignored (rejected as extra under @jsonStrict).
  • OmitValue[A]: encode-only — a present key is decoded normally (no annotation for the decoder macro to hook).

Omitted plain fields need a constructor default (or an onMissing-providing type like Option) to decode.

Verification

oxygen-jsonJVM/compile, oxygen-schemaJVM/compile, utJVM/testOnly oxygen.json.JsonSpec (85 passed) and oxygen.schema.* all green.

Full write-up incl. assumptions + confidence score: report/OXY-147.md.

🤖 Generated with Claude Code

Mirror the jsonSecret/SecretValue/JsonEncoder.Secret pattern for
unconditional field suppression (never on the wire) rather than redaction.

- annotations: add @jsonOmit
- JsonEncoder: add `def omit`, Omit/OmitEncoder (addToObject = false); handle
  @jsonOmit in productDeriver
- OmitValue: new opaque wrapper with encoder + decoder givens
- DeriveProductJsonEncoder: emit Growable.empty for @jsonOmit (wins over flatten)
- DeriveProductJsonDecoder: drop omitted key from `keys`; reconstruct from
  onMissingFromObject/default (present key ignored)
- JsonSchema: hide @jsonOmit fields from the emitted schema
- predef/json: export jsonOmit + OmitValue
- tests: JsonSpec omit suite + schema emitter omit test

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant