Skip to content

Fix #6190: honor explicit @JsonView on standard Throwable properties - #6192

Merged
cowtowncoder merged 12 commits into
FasterXML:3.xfrom
adityabagla7:fix/6190-throwable-explicit-view
Sep 8, 2026
Merged

cowtowncoder merged 12 commits into
FasterXML:3.xfrom
adityabagla7:fix/6190-throwable-explicit-view

Conversation

@adityabagla7

@adityabagla7 adityabagla7 commented Sep 6, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6190.

Problem

#6174 made ThrowableDeserializer honor @JsonView, and exempted the standard Throwable properties from view filtering via _isStandardThrowableProperty(). That exemption was needed because un-annotated properties default to exclusion (NO_VIEWS) under MapperFeature.DEFAULT_VIEW_INCLUSION disabled.

However, because the exemption was applied at deserialize time based on the property's name alone, an explicit @JsonView placed on one of those properties (e.g. by overriding setStackTrace or initCause to restrict it to an internal view) was unconditionally bypassed.

Solution

Instead of adding state to SettableBeanProperty or bypassing checks at deserialize time, fix the view assignments at construction time where the distinction between explicit and defaulted views is known:

  1. In BeanDeserializerFactory.buildThrowableDeserializer():
    • For standard Throwable properties (stackTrace, cause) that have no explicit @JsonView annotations (propDef.findViews() == null), do not force default views (NO_VIEWS) onto them (setViews(null)). This leaves _viewMatcher == null, so they remain visible under any active view by default without requiring an exemption check during deserialization.
    • For standard Throwable properties that do have explicit @JsonView annotations (including on initCause or getCause), configure their explicit views onto the property.
  2. In SimpleBeanPropertyDefinition, implemented findViews() delegating to _member so views on initCause are recognized.
  3. In ThrowableDeserializer.deserializeFromObject(), remove the identity-based exemption bypass: standard view visibility (!prop.visibleInView(activeView)) now works uniformly for all properties, including standard Throwable properties.
  4. SettableBeanProperty remains completely unchanged (no new state/fields added).
  5. Comprehensive test coverage in ThrowableViewDeserializationBypassTest:
    • Explicit @JsonView on stackTrace under active view, excluded view, and no view
    • Explicit @JsonView on cause under active view and excluded view
    • Enforcement under DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES
    • Compatibility with PropertyNamingStrategy (e.g., snake_case)

Comment thread src/main/java/tools/jackson/databind/deser/SettableBeanProperty.java Outdated
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.94% 📉 -0.010%
Branches branches 75.56% 📈 +0.010%

Coverage data generated from JaCoCo test results

…` properties

`ThrowableDeserializer` exempts standard `Throwable` properties from view
filtering, because without views they default out of every view under
`MapperFeature.DEFAULT_VIEW_INCLUSION` disabled. However, exempting them
based on property identity in `ThrowableDeserializer` unconditionally bypassed
explicit `@JsonView` annotations placed on those properties (e.g. overriding
`setStackTrace` or `initCause` to restrict them to an internal view).

Fix where views are assigned without adding state to `SettableBeanProperty`:
- In `BeanDeserializerFactory.buildThrowableDeserializer()`, do not force default
  views (`NO_VIEWS`) onto standard `Throwable` properties (`stackTrace`, `cause`)
  that lack explicit `@JsonView` annotations, allowing them to remain visible
  under any view.
- When an explicit `@JsonView` is configured on `stackTrace` or `cause` (including
  via `initCause` or `getCause`), configure its explicit view matcher.
- Support `findViews()` on `SimpleBeanPropertyDefinition`.
- In `ThrowableDeserializer.deserializeFromObject()`, remove the identity-based
  exemption bypass so standard view visibility checks apply uniformly.
@adityabagla7
adityabagla7 force-pushed the fix/6190-throwable-explicit-view branch from 5e022e6 to 24d475e Compare September 6, 2026 17:38
@cowtowncoder cowtowncoder added the cla-needed PR looks good (although may also require code review), but CLA needed from submitter label Sep 7, 2026
@cowtowncoder

Copy link
Copy Markdown
Member

Looks promising. Before I can merge, just need to make sure you we have a CLA from you @adityabagla7. If you haven't sent one, it's from https://github.com/FasterXML/jackson/blob/main/CLA-jackson-2026.pdf and is usually easiest to do by printing it, filling & signing, scan/photo, email to cla at fasterxml dot com. Only needs to be done once before the first contribution.

Looking forward to merging this!

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.96% 📈 +0.010%
Branches branches 75.60% 📈 +0.050%

Coverage data generated from JaCoCo test results

@adityabagla7

Copy link
Copy Markdown
Contributor Author

Thanks @cowtowncoder! I have just emailed the signed CLA to cla@fasterxml.com. Looking forward to having this merged!

@cowtowncoder cowtowncoder added cla-received PR already covered by CLA (optional label) and removed cla-needed PR looks good (although may also require code review), but CLA needed from submitter labels Sep 7, 2026
@cowtowncoder

Copy link
Copy Markdown
Member

@adityabagla7 Thank you for sending CLA super quickly! I hope to get the review complete and merge soon -- hopefully tomorrow.

@JooHyukKim JooHyukKim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Others may think differenlty, but the tests volume is sufficient for dedicated test class, WDYT?

if (views == null) {
for (BeanPropertyDefinition pd : beanDesc.findProperties()) {
if ("cause".equals(pd.getInternalName())) {
views = pd.findViews();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

null check needed right?
Should only assign to views if not null and also break only if non-null views found.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Updated so it only assigns and breaks when non-null views are found.

… cause views lookup

- Move explicit @JSONVIEW tests into dedicated ThrowableViewExplicit6190Test
- In BeanDeserializerFactory, only assign and break when non-null views are found on cause property definition
@adityabagla7

Copy link
Copy Markdown
Contributor Author

Agreed @JooHyukKim! I have moved the explicit view tests into a dedicated test class ThrowableViewExplicit6190Test to keep ThrowableViewDeserializationBypassTest focused on the standard property exemptions.

@gitar-bot

gitar-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 3 resolved / 3 findings

Honors explicit @JsonView annotations on standard Throwable properties by fixing view assignments at construction time rather than bypassing checks during deserialization. Resolves three issues: corrected Javadoc for _visibleInView, ensured message and suppressed properties respect FAIL_ON_UNEXPECTED_VIEW_PROPERTIES, and fixed explicit view handling when DEFAULT_VIEW_INCLUSION is disabled. Comprehensive test coverage validates view filtering across all standard Throwable properties.

✅ 3 resolved
✅ Quality: Javadoc for _shouldSkipNullValue detached, now docs _visibleInView

📄 src/main/java/tools/jackson/databind/deser/jdk/ThrowableDeserializer.java:467-481
The new _visibleInView method was inserted between the existing Javadoc block ("Helper method to check if a property with null value should be skipped ... @SInCE 3.1") and the _shouldSkipNullValue method it documents. The result is two stacked Javadoc comments above _visibleInView, while _shouldSkipNullValue is left with none and the misleading @since 3.1 doc. Move _visibleInView (with its own Javadoc) above the _shouldSkipNullValue doc block, or delete the now-orphaned comment, so each method keeps its correct documentation.

✅ Edge Case: message/suppressed view-skip ignores FAIL_ON_UNEXPECTED_VIEW_PROPERTIES

📄 src/main/java/tools/jackson/databind/deser/jdk/ThrowableDeserializer.java:332-338 📄 src/main/java/tools/jackson/databind/deser/jdk/ThrowableDeserializer.java:356-361
For settable standard properties the read loop honors DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES (lines 282-292), reporting a mismatch when a property falls outside the active view. The new view-exclusion branches for the non-settable "message" and "suppressed" properties simply p.skipChildren(); continue; and never raise that error, so an out-of-view explicit @JsonView on these two is silently ignored even when the feature is enabled. Consider mirroring the FAIL_ON_UNEXPECTED_VIEW_PROPERTIES check in these branches for consistent behavior.

✅ Edge Case: Explicit view on message/suppressed ignored if DEFAULT_VIEW_INCLUSION on

📄 src/main/java/tools/jackson/databind/deser/jdk/ThrowableDeserializer.java:273 📄 src/main/java/tools/jackson/databind/deser/jdk/ThrowableDeserializer.java:335 📄 src/main/java/tools/jackson/databind/deser/jdk/ThrowableDeserializer.java:358
activeView is only resolved when _needViewProcesing is true, which (via _anyViews) is true either because DEFAULT_VIEW_INCLUSION is disabled (the 3.x default) or because some bound SettableBeanProperty carries views. "message" and "suppressed" are not bound as settable properties, so a class that annotates only getMessage/getSuppressed and runs with DEFAULT_VIEW_INCLUSION explicitly enabled yields _needViewProcesing == false; activeView is then null and _visibleInView short-circuits to visible, silently ignoring the explicit view. Tests pass only because the default mapper disables DEFAULT_VIEW_INCLUSION. This is a narrow edge case but worth guarding (e.g. force view processing when messageViews/suppressedViews are non-null).

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 82.26% 📈 +0.310%
Branches branches 75.83% 📈 +0.280%

Coverage data generated from JaCoCo test results

@cowtowncoder
cowtowncoder merged commit 226e67c into FasterXML:3.x Sep 8, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-received PR already covered by CLA (optional label)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Explicit @JsonView on a standard Throwable property is ignored by ThrowableDeserializer

3 participants