Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0064c6c
Fix #5745: handle new JsonApplyView annotation
Mar 9, 2026
74e2d79
Merge branch 'FasterXML:3.x' into 3.x
f-aubert Mar 9, 2026
9ae5409
Merge branch 'FasterXML:3.x' into 3.x
f-aubert Mar 10, 2026
c2a0e0e
Fix #5745: implements findApplyView
Mar 11, 2026
185ef8a
Fix #5745: clones SerializationContextExt with seenObjectIds and obje…
Mar 11, 2026
328f47a
Merge branch '3.x' into 3.x
cowtowncoder Mar 11, 2026
bbf5476
Fix #5745: performance improvement (saving applyView in BeanPropertyW…
Mar 13, 2026
3c70196
Merge branch '3.x' into 3.x
cowtowncoder Mar 30, 2026
8821a19
Merge branch 'FasterXML:3.x' into 3.x
f-aubert Apr 15, 2026
f8c1e2a
Fix #5745: change implementation to modify activeView
Apr 15, 2026
b2c411e
Merge branch '3.x' into 3.x
cowtowncoder Apr 17, 2026
bea9481
Fix #5745: performance improvement (hotpath as before)
Apr 18, 2026
6146639
Merge branch '3.x' into 3.x
cowtowncoder Apr 21, 2026
9db6b7c
Merge branch '3.x' into f-aubert/3.x
cowtowncoder Apr 22, 2026
4ddadd2
Merge branch '3.x' into 3.x
cowtowncoder Apr 22, 2026
d3d3070
...
cowtowncoder Apr 22, 2026
d40be8a
undo accidental commit
cowtowncoder Apr 22, 2026
5ba99b2
Refactored to use new "withActiveView()" method in `SerializationCont…
cowtowncoder Apr 22, 2026
d6f17fa
Merge branch '3.x' into f-aubert/3.x
cowtowncoder Apr 22, 2026
118ed99
Remove extra line
cowtowncoder Apr 22, 2026
3cd6b8d
Merge branch '3.x' into 3.x
cowtowncoder Apr 22, 2026
66118f7
Merge branch '3.x' into 3.x
cowtowncoder Apr 28, 2026
70274a5
Fix #5745: adding unit tests (noneView, nesting)
Apr 29, 2026
4bec609
Merge branch '3.x' into 3.x
cowtowncoder Apr 30, 2026
36c261d
Merge branch '3.x' into 3.x
cowtowncoder May 1, 2026
2fe4f0a
Fix compilation problem wrt @JsonApplyView defaulting
cowtowncoder May 4, 2026
184f7a7
Minor clean up
cowtowncoder May 4, 2026
023f682
Extend test coverage
cowtowncoder May 4, 2026
fdc5a72
Add release notes
cowtowncoder May 4, 2026
9e3834c
Last small fixes
cowtowncoder May 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,10 @@ Martin Uhlen (@MartinUhlen)
absent field same as explicit `null`
[3.2.0]

Frederic Aubert (@f-aubert)
* Contributed #5745: Ability to change active JsonView on submodels (with `@JsonApplyView`)
[3.2.0]

David Nelson (@eatdrinksleepcode)
* Reported #5814: Enum deserialization does not respect
`JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES` override
Expand Down
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ Versions: 3.x (for earlier see VERSION-2.x)
#5734: `DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES` treats
absent field same as explicit `null`
(reported by Martin U)
#5745: Ability to change active JsonView on submodels (with `@JsonApplyView`)
(contributed by Frederic A)
#5821: Fix dead code and side-effect bug in `BeanPropertyWriter.toString()`
(fix by @pjfanning)
#5851: Regression of `JsonTypeInfo.Id.MINIMAL_CLASS` in the 3.x branch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,6 @@ public Class<?>[] findViews(MapperConfig<?> config, Annotated a) {
@Override
public Class<?> findApplyView(MapperConfig<?> config, Annotated a)
{
/* Theoretically this could be trickier, if multiple introspectors
* return non-null entries. For now, though, we'll just consider
* first one to return non-null to win.
*/
Class<?> result = _primary.findApplyView(config, a);
if (result == null) {
result = _secondary.findApplyView(config, a);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,23 @@ public AnnotatedMember getNonConstructorMutator() {
*/
public Class<?>[] findViews() { return null; }

/**
* Method used to find an override view that should be activated when
* processing this property's value (and any nested values reached through
* it), as configured by {@code @JsonApplyView}.
*<p>
* Unlike {@link #findViews()} (which lists views in which the property
* itself is included), this returns the view to make active while the
* value is being serialized. Special marker
* {@code JsonApplyView.NONE} indicates that view processing should be
* disabled (active view set to {@code null}) for the property and its subtree.
*
* @return Override view to apply, or {@code null} if no override is configured
*
* @since 3.2
*/
public Class<?> findApplyView() { return null; }

/**
* Method used to find whether property is part of a bi-directional
* reference.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,11 @@ public Class<?>[] findViews() {
return _annotationIntrospector.findViews(_config, getPrimaryMember());
}

@Override
public Class<?> findApplyView() {
return _annotationIntrospector.findApplyView(_config, getPrimaryMember());
}

@Override
public AnnotationIntrospector.ReferenceProperty findReferenceType() {
// 30-Mar-2017, tatu: Access lazily but retain information since it needs
Expand Down
65 changes: 55 additions & 10 deletions src/main/java/tools/jackson/databind/ser/BeanPropertyWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.lang.reflect.Field;
import java.util.HashMap;

import com.fasterxml.jackson.annotation.JsonApplyView;
import com.fasterxml.jackson.annotation.JsonInclude;

import tools.jackson.core.JacksonException;
Expand Down Expand Up @@ -177,6 +178,13 @@ public class BeanPropertyWriter
*/
protected final Class<?>[] _includeInViews;

/**
* View to apply for this property when applyView is available for the Bean.
*
* @since 3.2
*/
protected final Class<?> _applyView;

/**
* Inclusion settings for this property, pre-computed in {@code PropertyBuilder}
* by merging global defaults, type defaults, and property-level annotations,
Expand Down Expand Up @@ -214,21 +222,39 @@ public BeanPropertyWriter(BeanPropertyDefinition propDef,
{
this(propDef, member, contextAnnotations, declaredType,
ser, typeSer, serType, suppressNulls, suppressableValue,
includeInViews, null);
includeInViews, null, null);
}

/**
* @deprecated Since 3.2 use {@link #BeanPropertyWriter(BeanPropertyDefinition,
* AnnotatedMember, Annotations, JavaType, ValueSerializer, TypeSerializer,
* JavaType, boolean, Object, Class[], JsonInclude.Value, Class)} instead.
*/
@Deprecated // @since 3.2
public BeanPropertyWriter(BeanPropertyDefinition propDef,
AnnotatedMember member, Annotations contextAnnotations,
JavaType declaredType,
ValueSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
boolean suppressNulls, Object suppressableValue,
Class<?>[] includeInViews, JsonInclude.Value inclusion)
{
this(propDef, member, contextAnnotations, declaredType,
ser, typeSer, serType, suppressNulls, suppressableValue,
includeInViews, inclusion, null);
}

/**
* Constructor with additional inclusion parameter.
* Constructor with additional inclusion and applyView parameter.
*
* @since 3.1
* @since 3.2
*/
@SuppressWarnings("unchecked")
public BeanPropertyWriter(BeanPropertyDefinition propDef,
AnnotatedMember member, Annotations contextAnnotations,
JavaType declaredType,
ValueSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
boolean suppressNulls, Object suppressableValue,
Class<?>[] includeInViews, JsonInclude.Value inclusion)
Class<?>[] includeInViews, JsonInclude.Value inclusion, Class<?> applyView)
{
super(propDef);
_member = member;
Expand Down Expand Up @@ -260,6 +286,7 @@ public BeanPropertyWriter(BeanPropertyDefinition propDef,
// this will be resolved later on, unless nulls are to be suppressed
_nullSerializer = null;
_includeInViews = includeInViews;
_applyView = applyView;
_inclusion = (inclusion == null) ? JsonInclude.Value.empty() : inclusion;
}

Expand All @@ -276,6 +303,7 @@ protected BeanPropertyWriter() {
_name = null;
_wrapperName = null;
_includeInViews = null;
_applyView = null;

_declaredType = null;
_serializer = null;
Expand Down Expand Up @@ -323,6 +351,7 @@ protected BeanPropertyWriter(BeanPropertyWriter base, PropertyName name) {
_suppressNulls = base._suppressNulls;
_suppressableValue = base._suppressableValue;
_includeInViews = base._includeInViews;
_applyView = base._applyView;
_typeSerializer = base._typeSerializer;
_nonTrivialBaseType = base._nonTrivialBaseType;
_inclusion = base._inclusion;
Expand All @@ -347,6 +376,7 @@ protected BeanPropertyWriter(BeanPropertyWriter base, SerializedString name) {
_suppressNulls = base._suppressNulls;
_suppressableValue = base._suppressableValue;
_includeInViews = base._includeInViews;
_applyView = base._applyView;
_typeSerializer = base._typeSerializer;
_nonTrivialBaseType = base._nonTrivialBaseType;
_inclusion = base._inclusion;
Expand Down Expand Up @@ -660,10 +690,12 @@ public void serializeAsProperty(Object bean, JsonGenerator g, SerializationConte
}
}
g.writeName(_name);
if (_typeSerializer == null) {
ser.serialize(value, g, ctxt);
if (_applyView == null) {
_serialize(value, g, ctxt, ser);
} else {
ser.serializeWithType(value, g, ctxt, _typeSerializer);
ValueSerializer<Object> actualSer = ser;
ctxt.withActiveView(_applyView != JsonApplyView.NONE.class ? _applyView : null,
() -> _serialize(value, g, ctxt, actualSer));
}
}

Expand Down Expand Up @@ -728,10 +760,13 @@ public void serializeAsElement(Object bean, JsonGenerator g, SerializationContex
return;
}
}
if (_typeSerializer == null) {
ser.serialize(value, g, ctxt);

if (_applyView == null) {
_serialize(value, g, ctxt, ser);
} else {
ser.serializeWithType(value, g, ctxt, _typeSerializer);
ValueSerializer<Object> actualSer = ser;
ctxt.withActiveView(_applyView != JsonApplyView.NONE.class ? _applyView : null,
() -> _serialize(value, g, ctxt, actualSer));
}
}

Expand All @@ -753,6 +788,16 @@ public void serializeAsOmittedElement(Object bean, JsonGenerator g,
}
}

// @since 3.2
private void _serialize(Object value, JsonGenerator g, SerializationContext ctxt,
ValueSerializer<Object> ser) {
if (_typeSerializer == null) {
ser.serialize(value, g, ctxt);
} else {
ser.serializeWithType(value, g, ctxt, _typeSerializer);
}
}

/*
/**********************************************************************
/* PropertyWriter methods (schema generation)
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/tools/jackson/databind/ser/PropertyBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,15 @@ protected BeanPropertyWriter buildWriter(SerializationContext ctxt,
if (views == null) {
views = _beanDesc.findDefaultViews();
}
Class<?> applyView = propDef.findApplyView();

// [databind#1649]: Pass the computed inclusion value (which includes
// contextual annotations) so BeanPropertyWriter can use it directly
// instead of re-computing in findPropertyInclusion()
BeanPropertyWriter bpw = _constructPropertyWriter(propDef,
am, _beanDesc.getClassAnnotations(), declaredType,
ser, typeSer, serializationType, suppressNulls, valueToSuppress, views,
inclV);
inclV, applyView);

// How about custom null serializer?
Object serDef = _annotationIntrospector.findNullSerializer(_config, am);
Expand Down Expand Up @@ -285,12 +287,12 @@ protected BeanPropertyWriter _constructPropertyWriter(BeanPropertyDefinition pro
JavaType declaredType,
ValueSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
boolean suppressNulls, Object suppressableValue,
Class<?>[] includeInViews, JsonInclude.Value inclusion)
Class<?>[] includeInViews, JsonInclude.Value inclusion, Class<?> applyView)
{
return new BeanPropertyWriter(propDef,
member, contextAnnotations, declaredType,
ser, typeSer, serType, suppressNulls, suppressableValue, includeInViews,
inclusion);
inclusion, applyView);
}

/*
Expand Down
Loading