Skip to content

PR for JsonApplyView (#5745)#5754

Draft
f-aubert wants to merge 13 commits intoFasterXML:3.xfrom
f-aubert:3.x
Draft

PR for JsonApplyView (#5745)#5754
f-aubert wants to merge 13 commits intoFasterXML:3.xfrom
f-aubert:3.x

Conversation

@f-aubert
Copy link
Copy Markdown

As discussed, here a Draft PR.

Comment thread src/main/java/tools/jackson/databind/introspect/AnnotationIntrospectorPair.java Outdated
}
}

private SerializationContext getContext(SerializationContext context) {
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.

Ugh. No, this adds way too much per-property write overhead -- must NOT be done on per-call basis. That is, things need to be pre-processed when constructing/initializing BeanPropertyWriters; especially annotation introspection.

Also, even then, should not be constructing new SerializationConfigs or -Contexts on critical path -- just overriding active view (_activeView, needs to change to non-final) in SerializationContext before, resetting after.

Might be possible to wrap BeanPropertyWriter to do that... ?

* @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
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
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
Author

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

@f-aubert
Copy link
Copy Markdown
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.

public Class<?> findApplyView(MapperConfig<?> config, Annotated a)
{
JsonApplyView ann = _findAnnotation(a, JsonApplyView.class);
return (ann == null) ? null : ann.value();
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.

I think this should translate JsonApplyView.NONE.class into null so callers need do the translation or know about special casing.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Don't we need to differentiate between

  • JsonApplyView.NONE.class (for this property / serialization we don't want to apply any view aka setActiveView to null) and
  • NULL (for this property / seriailzation we don't want to change anything to the current activeView) and process views as until now in Jackson
    -> I think we need to document this NONE class but cannot totally hide it. It is also a special use case since the normal case will be to replace with another view and not suppress the current one.

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.

Hmmmh. If there is use case of forcing Active View to be set to null, yes, a placeholder needed I suppose.

So documenting this makes sense, then, and letting NONE.class be exposed.

@f-aubert
Copy link
Copy Markdown
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
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
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
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
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
@cowtowncoder
Copy link
Copy Markdown
Member

Will try to get annotations PR sorted today, first, then get back here.

@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.58% 📈 +0.000%
Branches branches 74.86% 📉 -0.010%

Coverage data generated from JaCoCo test results

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