Skip to content

PR for using @JsonApplyView (#5745)#5754

Merged
cowtowncoder merged 30 commits into
FasterXML:3.xfrom
f-aubert:3.x
May 4, 2026
Merged

PR for using @JsonApplyView (#5745)#5754
cowtowncoder merged 30 commits into
FasterXML:3.xfrom
f-aubert:3.x

Conversation

@f-aubert
Copy link
Copy Markdown
Contributor

@f-aubert f-aubert commented Mar 10, 2026

As discussed, here a Draft PR for #5745.

Comment thread src/main/java/tools/jackson/databind/introspect/AnnotationIntrospectorPair.java Outdated
Comment thread src/main/java/tools/jackson/databind/introspect/AnnotationIntrospectorPair.java Outdated
Comment thread src/main/java/tools/jackson/databind/ser/BeanPropertyWriter.java Outdated
* @return view (represented by class) that the property will be processed with;
* if null, processing will use the current view if any
*/
public Class<?> findApplyView(MapperConfig<?> config, Annotated a) { return null; }
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.

Should the translation of "no view" be handled here?

(if so, marker effectively means "no override", same as no annotation -- except that allows for mix-ins and sub-classes to override and disable @JsonApplyView of target/base class).

@f-aubert
Copy link
Copy Markdown
Contributor Author

f-aubert commented Mar 12, 2026

@cowtowncoder thanks for supporting and helping me. You suggested the implementation shall go another direction with a caching of BeanWriterProperty and not cloning SerializationContext/SerializationConfig although it always check first if active view has changed or not and avoid unnecessary cloning (minimal performance impact?). Shall I attempt to find out where else we can do that, or do you have something specific in mind?
On an administrative note, shall we commit further on this PR or shall we start from a clean state with another branch and PR? Maybe you could create a branch on your side with TODOs and placeholders and I will fork and fill them in. I'm not very expert in github / prs and so on.
Have a good day

@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder in the meanwhile I reworked the handling in BeanWriterProperty to read the annotation just once. Maybe it's enough so, as the SerializationContext creation happens only when needed and is ultimately just a copy by reference of the properties. If you still wish to make the activeView accessible, save it before and restore it after the property it should be quite easy as well. But then you possibly have an activeView not matching its config...

@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder would you prefer another cleaner push request to be able to merge it easily?

@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder is this implementation fine enough or would you prefer to mutate the context instead.

@cowtowncoder
Copy link
Copy Markdown
Member

cowtowncoder commented Mar 30, 2026

Ok, sorry, so no, not good as-is -- I don't think new SerializationConfig or -Context instances should be created on the fly.

Instead, active view in SerializationContext:

final protected Class<?> _activeView;

needs to be changed mutable. Method could then be added, something like

    void withView(Class<?> newActiveView, /* or whatever callback interface */ Runnable callback) {
        Class<?> oldView = _activeView;
        _activeView = newActiveView;
        try {
            callback.run();
        } finally {
            _activeView = oldView;
        }
    }

which would switch view around call.

As to this or new PR, no Strong opinion, either way fine with me.

During PR could also temporarily add new annotation in databind package to make code compile & CI run.

@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder I managed to revert the cloning of Context and Config and just modify the activeView in BeanPropertyWriter. Can you review my change? And possibly move forward with this PR? Thanks

protected final Class<?>[] _includeInViews;

/**
* Alternate set of property writers used when applyView is
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.

Copy-pasted?

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.

Yes, I suggest the following:
/**
* View to apply for this property when applyView is available for the Bean.
*
* @SInCE 3.2
*/


Class<?> currentActiveView = ctxt.getActiveView();
try {
ctxt.setActiveView(getAppliedView(ctxt));
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.

This now adds overhead for every write call on hot path.
Not good. Should check if _applyView is null, if so, fast patch with no changes; if not null, then handle active view.

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.

I did it as asked. Please review again

@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder here the corrections.

@cowtowncoder cowtowncoder added the cla-needed PR looks good (although may also require code review), but CLA needed from submitter label Apr 18, 2026
@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder did you get the cla? And does the change suits you? Thks

@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 Apr 21, 2026
@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder I added some more test (or more precisely more complete tests) combining applying another view, suppressing view, and nesting beans. Any other idea of what we shall test? Once again thanks for your involvement and looking forward to 3.2.0

@f-aubert f-aubert marked this pull request as ready for review April 29, 2026 20:22
@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.60% 📈 +0.000%
Branches branches 74.93% 📈 +0.000%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.59% 📈 +0.000%
Branches branches 74.93% 📈 +0.020%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.60% 📈 +0.010%
Branches branches 74.93% 📈 +0.020%

Coverage data generated from JaCoCo test results

public Bean beanWithApplyViewB = new Bean();

@JsonView(ViewA.class)
@JsonApplyView
Copy link
Copy Markdown
Member

@cowtowncoder cowtowncoder May 1, 2026

Choose a reason for hiding this comment

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

Hmmmh. Should we actually allow this at all -- or require explicit use of NONE.class?

Looking at this case it is not obvious to me that plain @JsonApplyView means "disable View altogether". I would prefer that it'd need to be explicit like:

@JsonApplyView(NONE.class)

or -- perhaps -- either:

  1. Keep one constant but rename as NO_VIEW
  2. Keep NONE as default but mean "@JsonApplyView that does nothing", add NO_VIEW or DISABLE_VIEW to mean setting Active View to null (so no View processing).

Bean2 bean2 = new Bean2();

StringWriter sw = new StringWriter();
MAPPER.writerWithView(ViewA.class).writeValue(sw, bean2);
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.

nit: could just use writeValueAsString() instead of StringWriter.

@cowtowncoder
Copy link
Copy Markdown
Member

@cowtowncoder I added some more test (or more precisely more complete tests) combining applying another view, suppressing view, and nesting beans. Any other idea of what we shall test? Once again thanks for your involvement and looking forward to 3.2.0

Good stuff! I think test coverage may be ok now.

But one thing I realized -- and commented about -- was whether use of default value for @JsonApplyView (and naming of NONE) is a good idea wrt readability.
So maybe:

  1. Should not define any default and
  2. should rename NONE as NO_VIEW (or something)?

alternatively if we wanted to allow @JsonApplyView as no-op (do nothing), would have 2 constants, but I am not sure there is much point doing that.

Aside from this one last concern I think we are done.

@f-aubert
Copy link
Copy Markdown
Contributor Author

f-aubert commented May 2, 2026

I also see three options

  1. as it
  2. not defaulting to NONE/NO_VIEW but to ACTIVE/CURRENT/NO_OP
  3. another annotation JsonSuppressView or JsonApplyNoView

As for me I could live with any of the three. The NoOp does not seem necessary to me because semantically you want to apply a view or suppress a view for a given property and just documenting the special value should be enough. So the current implementation. But if we go with 2) then for the sake of completeness we should add the active special value anyway. The last option would obviously be more explicit but what if both annotation are used on the same property. Not to mention it add some more work.

@cowtowncoder
Copy link
Copy Markdown
Member

I also see three options

  • as it is
  • not defaulting to NONE/NO_VIEW but to ACTIVE/CURRENT/NO_OP
  • another annotation JsonSuppressView or JsonApplyNoView

As for me I could live with any of the three. The NoOp does not seem necessary to me because > semantically you want to apply a view or suppress a view for a given property and just
documenting the special value should be enough. So the current implementation. But if we go
with 2) then for the sake of completeness we should add the active special value anyway. The
last option would obviously be more explicit but what if both annotation are used on the same > property. Not to mention it add some more work.

I don't think what you list cover same cases as mine do.

Now: for me separate annotation seems like unnecessary, so no for option 3.

But wrt "no-op", to me the only use would be as mix-in override to "disable" @JsonApplyView on class, with a mix-in. And that is probably not a common use case, can defer to see if needed.

What I mean by NO_VIEW is different tho: that means setting Active View to null.
Whereas I think ACTIVE/CURRENT would mean "use whatever is already Active View (do not change).

@cowtowncoder
Copy link
Copy Markdown
Member

Ok, so I do want to prevent use of plain

 @JsonApplyView

without argument. And question then is whether constant NONE is good -- for semantics of "set Active View to null" (disable View processing).
Maybe it is? If so, just removing default NONE.class is all that is needed.

@cowtowncoder
Copy link
Copy Markdown
Member

cowtowncoder commented May 4, 2026

Made change via FasterXML/jackson-annotations#347 (with minor Javadoc changes).

@f-aubert
Copy link
Copy Markdown
Contributor Author

f-aubert commented May 4, 2026

@cowtowncoder I think it makes perfectly sense to just drop the default forcing usage of the special value class to force the view to NULL. I wanted to thank you for actively contributing and supporting this feature and PR. I'm still amazed by your work and contribution in this great library. Looking forward to using the release candidate 3.2.0 ;)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.60% 📈 +0.010%
Branches branches 74.93% 📈 +0.020%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.60% 📈 +0.010%
Branches branches 74.92% 📈 +0.010%

Coverage data generated from JaCoCo test results

@cowtowncoder cowtowncoder changed the title PR for JsonApplyView (#5745) PR for using @JsonApplyView (#5745) May 4, 2026
@cowtowncoder cowtowncoder merged commit 58cd0eb into FasterXML:3.x May 4, 2026
6 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.60% 📈 +0.010%
Branches branches 74.92% 📈 +0.010%

Coverage data generated from JaCoCo test results

@cowtowncoder
Copy link
Copy Markdown
Member

@f-aubert Finally found time to finish up merging. Phew!

Thank you for all your work here: should be good for 3.2.0.

And maybe add deserialization support, probably for 3.3 (I am planning to finalize 3.2.0 this or next week).

@f-aubert
Copy link
Copy Markdown
Contributor Author

@cowtowncoder : how does it look like with first release candidate of Jackson 3.2? If you want to start discussing the deserialization now or later, I'm ready to help or discuss

@cowtowncoder
Copy link
Copy Markdown
Member

@f-aubert Bit slower than planned, but planning notes are here:

FasterXML/jackson-future-ideas#106

so probably skipping RCs altogether. But will also need Jackson 2.22(.0) released first.
And due to flow of vuln fixes for LTS versions (2.18, 2.21, 3.1), may need/want to push patches for those first too.

But if you could file an issue for "Deserialization support for @JsonApplyView" that'd be good first step I think.

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.

2 participants