Skip to content

docs: document cds.drafts.enforceReadonly and the @readonly bypass hint - #2790

Open
rjayasinghe wants to merge 3 commits into
mainfrom
enforce_readonly
Open

docs: document cds.drafts.enforceReadonly and the @readonly bypass hint#2790
rjayasinghe wants to merge 3 commits into
mainfrom
enforce_readonly

Conversation

@rjayasinghe

@rjayasinghe rjayasinghe commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

What

Adds prose documentation for the cds.drafts.enforceReadonly property in java/fiori-drafts.md (new Read-Only Fields in Drafts section):

  • Explains that @readonly / @Core.Computed are enforced only at activation by default, and that setting cds.drafts.enforceReadonly: true enforces them on the draft itself during DRAFT_NEW / DRAFT_PATCH (so read-only fields can't be changed via OData PATCH on the draft).
  • Documents the statement hint .hint("@readonly", false) to intentionally write read-only / computed fields from trusted custom code (e.g. determinations), with a warning that managed (@cds.on.insert/@cds.on.update) and @Core.Immutable fields remain enforced regardless.

Why

The property already appears in the generated properties table but had no prose explaining the custom-code implication or the bypass hint, which surfaced in a developer question.

Verification

  • npm run docs:build passes with no dead-link errors; the property cross-link anchor #cds-drafts-enforcereadonly matches the generated id.
  • Hint and behavior verified against the CAP Java runtime source (ReadOnlyHandler).

Explain that @readonly/@Core.Computed are enforced on drafts (during
DRAFT_NEW/DRAFT_PATCH) when cds.drafts.enforceReadonly is enabled, and
document the .hint("@readonly", false) statement hint to write such
fields from trusted custom code.

Closes cds-java/home#2828
@smahati

smahati commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Hey @mofterdinger Could you provide your feedback for this PR? Thank you :)

@smahati
smahati requested a review from renejeglinsky as a code owner August 20, 2026 12:34
Comment thread java/fiori-drafts.md

By default, `@readonly` and `@Core.Computed` fields are only enforced when a draft is activated, that means during the `CREATE` or `UPDATE` event on the active entity. Until then, such fields can still be changed on the draft, for example through an OData `PATCH` request.

To enforce these annotations on the draft already, during the `DRAFT_NEW` and `DRAFT_PATCH` events, set the [`cds.drafts.enforceReadonly`](./developing-applications/properties#cds-drafts-enforcereadonly) property (default `false`):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To enforce these annotations on the draft already, during the `DRAFT_NEW` and `DRAFT_PATCH` events, set the [`cds.drafts.enforceReadonly`](./developing-applications/properties#cds-drafts-enforcereadonly) property (default `false`):
To enforce these annotations on the draft even before activation, during the `DRAFT_NEW` and `DRAFT_PATCH` events, set the [`cds.drafts.enforceReadonly`](./developing-applications/properties#cds-drafts-enforcereadonly) property (default `false`):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it doesn't even need the "even" :)

Suggested change
To enforce these annotations on the draft already, during the `DRAFT_NEW` and `DRAFT_PATCH` events, set the [`cds.drafts.enforceReadonly`](./developing-applications/properties#cds-drafts-enforcereadonly) property (default `false`):
To enforce these annotations on the draft before activation, during the `DRAFT_NEW` and `DRAFT_PATCH` events, set the [`cds.drafts.enforceReadonly`](./developing-applications/properties#cds-drafts-enforcereadonly) property (default `false`):

@mofterdinger

Copy link
Copy Markdown
Contributor

Hi, sorry, I can't provide any helpful review feedback, I wasn't involved in implementing this feature. Will remove my assignment.
Thanks,
Markus

@mofterdinger
mofterdinger removed their request for review September 9, 2026 09:33
@rjayasinghe

Copy link
Copy Markdown
Contributor Author

I guess @beckermarc is the better candidate. :)

Comment thread java/fiori-drafts.md
During activation the draft data is deleted from the database. This happens before the active entity is created or updated within the same transaction.
In case the create or update operation raises an error, the transaction is rolled back and the draft data is restored.

## Read-Only Fields in Drafts { #readonly-in-drafts }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also explain the effects for readonly elements calculated in code (determinations). In the default scenario determinations need to happen during draft activation on CREATE or UPDATE. They can optionally happen at draft edit time as well (to show the determined field on the UI already in that mode). If the determination is not fully deterministic (e.g. creating a random UUID) there is no guarantee that values created in draft mode and during activation are the same.

This can be solved by setting the enforceReadonly flag to false as well, as on that mode @readonly is no longer evaluated during activation, thus elements calculated in draft mode are taken over with the exact same value.

Comment thread java/fiori-drafts.md

### Writing Read-Only Fields from Custom Code { #readonly-hint }

When `cds.drafts.enforceReadonly` is enabled, the read-only enforcement also applies to `Update` or `Insert` statements that your own event handlers run against the draft entity, for example in a determination. As a result, values for `@readonly` and `@Core.Computed` fields are removed from these statements as well.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention here explicitly that this applies to statements run via the DraftService.

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.

5 participants