Skip to content

Commit d9c0332

Browse files
authored
#1296 @JsonIncludeProperties (#2771)
Implement #1296 (add and support `@JsonIncludeProperties`)
1 parent 5758c6b commit d9c0332

25 files changed

+931
-80
lines changed

src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java

+12
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,18 @@ public JsonIgnoreProperties.Value findPropertyIgnorals(Annotated ac)
278278
*/
279279
public Boolean isIgnorableType(AnnotatedClass ac) { return null; }
280280

281+
/**
282+
* Method for finding information about properties to include.
283+
*
284+
* @param ac Annotated class to introspect
285+
*
286+
* @since 2.12
287+
*/
288+
public JsonIncludeProperties.Value findPropertyInclusions(Annotated ac)
289+
{
290+
return JsonIncludeProperties.Value.all();
291+
}
292+
281293
/**
282294
* Method for finding if annotated class has associated filter; and if so,
283295
* to return id that is used to locate filter.

src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java

+11
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,17 @@ public JsonInclude.Value getDefaultInclusion(Class<?> baseType,
498498
public abstract JsonIgnoreProperties.Value getDefaultPropertyIgnorals(Class<?> baseType,
499499
AnnotatedClass actualClass);
500500

501+
/**
502+
* Helper method that may be called to see if there are property inclusion
503+
* definitions from annotations (via {@link AnnotatedClass}).
504+
*
505+
* TODO: config override.
506+
*
507+
* @since 2.12
508+
*/
509+
public abstract JsonIncludeProperties.Value getDefaultPropertyInclusions(Class<?> baseType,
510+
AnnotatedClass actualClass);
511+
501512
/**
502513
* Accessor for object used for determining whether specific property elements
503514
* (method, constructors, fields) can be auto-detected based on

src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java

+8
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,14 @@ public final JsonIgnoreProperties.Value getDefaultPropertyIgnorals(Class<?> base
665665
return JsonIgnoreProperties.Value.merge(base, overrides);
666666
}
667667

668+
@Override
669+
public final JsonIncludeProperties.Value getDefaultPropertyInclusions(Class<?> baseType,
670+
AnnotatedClass actualClass)
671+
{
672+
AnnotationIntrospector intr = getAnnotationIntrospector();
673+
return (intr == null) ? null : intr.findPropertyInclusions(actualClass);
674+
}
675+
668676
@Override
669677
public final VisibilityChecker<?> getDefaultVisibilityChecker()
670678
{

src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.annotation.JacksonInject;
1111
import com.fasterxml.jackson.annotation.JsonCreator;
1212
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
13+
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
1314
import com.fasterxml.jackson.annotation.JsonSetter;
1415
import com.fasterxml.jackson.annotation.Nulls;
1516
import com.fasterxml.jackson.annotation.JsonCreator.Mode;
@@ -1385,6 +1386,10 @@ public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
13851386
Set<String> ignored = (ignorals == null) ? null
13861387
: ignorals.findIgnoredForDeserialization();
13871388
md.setIgnorableProperties(ignored);
1389+
JsonIncludeProperties.Value inclusions = config.getDefaultPropertyInclusions(Map.class,
1390+
beanDesc.getClassInfo());
1391+
Set<String> included = inclusions == null ? null : inclusions.getIncluded();
1392+
md.setIncludableProperties(included);
13881393
deser = md;
13891394
}
13901395
}

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java

+38-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.databind.cfg.CoercionAction;
99
import com.fasterxml.jackson.databind.deser.impl.*;
1010
import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring;
11+
import com.fasterxml.jackson.databind.util.IgnorePropertiesUtil;
1112
import com.fasterxml.jackson.databind.util.NameTransformer;
1213
import com.fasterxml.jackson.databind.util.TokenBuffer;
1314

@@ -56,14 +57,31 @@ public class BeanDeserializer
5657

5758
/**
5859
* Constructor used by {@link BeanDeserializerBuilder}.
60+
*
61+
* @deprecated in 2.12, remove from 3.0
5962
*/
63+
@Deprecated
6064
public BeanDeserializer(BeanDeserializerBuilder builder, BeanDescription beanDesc,
6165
BeanPropertyMap properties, Map<String, SettableBeanProperty> backRefs,
6266
HashSet<String> ignorableProps, boolean ignoreAllUnknown,
6367
boolean hasViews)
6468
{
6569
super(builder, beanDesc, properties, backRefs,
66-
ignorableProps, ignoreAllUnknown, hasViews);
70+
ignorableProps, ignoreAllUnknown, null, hasViews);
71+
}
72+
73+
/**
74+
* Constructor used by {@link BeanDeserializerBuilder}.
75+
*
76+
* @since 2.12
77+
*/
78+
public BeanDeserializer(BeanDeserializerBuilder builder, BeanDescription beanDesc,
79+
BeanPropertyMap properties, Map<String, SettableBeanProperty> backRefs,
80+
HashSet<String> ignorableProps, boolean ignoreAllUnknown, Set<String> includableProps,
81+
boolean hasViews)
82+
{
83+
super(builder, beanDesc, properties, backRefs,
84+
ignorableProps, ignoreAllUnknown, includableProps, hasViews);
6785
}
6886

6987
/**
@@ -86,10 +104,21 @@ public BeanDeserializer(BeanDeserializerBase src, ObjectIdReader oir) {
86104
super(src, oir);
87105
}
88106

107+
/**
108+
* @deprecated in 2.12, remove from 3.0
109+
*/
110+
@Deprecated
89111
public BeanDeserializer(BeanDeserializerBase src, Set<String> ignorableProps) {
90112
super(src, ignorableProps);
91113
}
92114

115+
/**
116+
* @since 2.12
117+
*/
118+
public BeanDeserializer(BeanDeserializerBase src, Set<String> ignorableProps, Set<String> includableProps) {
119+
super(src, ignorableProps, includableProps);
120+
}
121+
93122
public BeanDeserializer(BeanDeserializerBase src, BeanPropertyMap props) {
94123
super(src, props);
95124
}
@@ -119,8 +148,8 @@ public BeanDeserializer withObjectIdReader(ObjectIdReader oir) {
119148
}
120149

121150
@Override
122-
public BeanDeserializer withIgnorableProperties(Set<String> ignorableProps) {
123-
return new BeanDeserializer(this, ignorableProps);
151+
public BeanDeserializer withIgnorableProperties(Set<String> ignorableProps, Set<String> includableProps) {
152+
return new BeanDeserializer(this, ignorableProps, includableProps);
124153
}
125154

126155
@Override
@@ -464,7 +493,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri
464493
continue;
465494
}
466495
// Things marked as ignorable should not be passed to any setter
467-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
496+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
468497
handleIgnoredProperty(p, ctxt, handledType(), propName);
469498
continue;
470499
}
@@ -694,7 +723,7 @@ protected Object deserializeWithUnwrapped(JsonParser p, DeserializationContext c
694723
continue;
695724
}
696725
// Things marked as ignorable should not be passed to any setter
697-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
726+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
698727
handleIgnoredProperty(p, ctxt, bean, propName);
699728
continue;
700729
}
@@ -751,7 +780,7 @@ protected Object deserializeWithUnwrapped(JsonParser p, DeserializationContext c
751780
}
752781
continue;
753782
}
754-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
783+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
755784
handleIgnoredProperty(p, ctxt, bean, propName);
756785
continue;
757786
}
@@ -850,7 +879,7 @@ protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p, Deseri
850879
continue;
851880
}
852881
// Things marked as ignorable should not be passed to any setter
853-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
882+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
854883
handleIgnoredProperty(p, ctxt, handledType(), propName);
855884
continue;
856885
}
@@ -942,7 +971,7 @@ protected Object deserializeWithExternalTypeId(JsonParser p, DeserializationCont
942971
continue;
943972
}
944973
// ignorable things should be ignored
945-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
974+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
946975
handleIgnoredProperty(p, ctxt, bean, propName);
947976
continue;
948977
}
@@ -1033,7 +1062,7 @@ protected Object deserializeUsingPropertyBasedWithExternalTypeId(JsonParser p, D
10331062
continue;
10341063
}
10351064
// Things marked as ignorable should not be passed to any setter
1036-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
1065+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
10371066
handleIgnoredProperty(p, ctxt, handledType(), propName);
10381067
continue;
10391068
}

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java

+58-7
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ public abstract class BeanDeserializerBase
135135
*/
136136
final protected Set<String> _ignorableProps;
137137

138+
/**
139+
* Keep track of the the properties that needs to be specifically included.
140+
*/
141+
final protected Set<String> _includableProps;
142+
138143
/**
139144
* Flag that can be set to ignore and skip unknown properties.
140145
* If set, will not throw an exception for unknown properties.
@@ -201,6 +206,7 @@ protected BeanDeserializerBase(BeanDeserializerBuilder builder,
201206
BeanDescription beanDesc,
202207
BeanPropertyMap properties, Map<String, SettableBeanProperty> backRefs,
203208
Set<String> ignorableProps, boolean ignoreAllUnknown,
209+
Set<String> includableProps,
204210
boolean hasViews)
205211
{
206212
super(beanDesc.getType());
@@ -211,6 +217,7 @@ protected BeanDeserializerBase(BeanDeserializerBuilder builder,
211217
_backRefs = backRefs;
212218
_ignorableProps = ignorableProps;
213219
_ignoreAllUnknown = ignoreAllUnknown;
220+
_includableProps = includableProps;
214221

215222
_anySetter = builder.getAnySetter();
216223
List<ValueInjector> injectables = builder.getInjectables();
@@ -263,6 +270,7 @@ protected BeanDeserializerBase(BeanDeserializerBase src, boolean ignoreAllUnknow
263270
_backRefs = src._backRefs;
264271
_ignorableProps = src._ignorableProps;
265272
_ignoreAllUnknown = ignoreAllUnknown;
273+
_includableProps = src._includableProps;
266274
_anySetter = src._anySetter;
267275
_injectables = src._injectables;
268276
_objectIdReader = src._objectIdReader;
@@ -288,6 +296,7 @@ protected BeanDeserializerBase(BeanDeserializerBase src, NameTransformer unwrapp
288296
_backRefs = src._backRefs;
289297
_ignorableProps = src._ignorableProps;
290298
_ignoreAllUnknown = (unwrapper != null) || src._ignoreAllUnknown;
299+
_includableProps = src._includableProps;
291300
_anySetter = src._anySetter;
292301
_injectables = src._injectables;
293302
_objectIdReader = src._objectIdReader;
@@ -325,6 +334,7 @@ public BeanDeserializerBase(BeanDeserializerBase src, ObjectIdReader oir)
325334
_backRefs = src._backRefs;
326335
_ignorableProps = src._ignorableProps;
327336
_ignoreAllUnknown = src._ignoreAllUnknown;
337+
_includableProps = src._includableProps;
328338
_anySetter = src._anySetter;
329339
_injectables = src._injectables;
330340

@@ -351,6 +361,14 @@ public BeanDeserializerBase(BeanDeserializerBase src, ObjectIdReader oir)
351361
}
352362

353363
public BeanDeserializerBase(BeanDeserializerBase src, Set<String> ignorableProps)
364+
{
365+
this(src, ignorableProps, src._includableProps);
366+
}
367+
368+
/**
369+
* @since 2.12
370+
*/
371+
public BeanDeserializerBase(BeanDeserializerBase src, Set<String> ignorableProps, Set<String> includableProps)
354372
{
355373
super(src._beanType);
356374
_beanType = src._beanType;
@@ -362,6 +380,7 @@ public BeanDeserializerBase(BeanDeserializerBase src, Set<String> ignorableProps
362380
_backRefs = src._backRefs;
363381
_ignorableProps = ignorableProps;
364382
_ignoreAllUnknown = src._ignoreAllUnknown;
383+
_includableProps = includableProps;
365384
_anySetter = src._anySetter;
366385
_injectables = src._injectables;
367386

@@ -375,9 +394,10 @@ public BeanDeserializerBase(BeanDeserializerBase src, Set<String> ignorableProps
375394

376395
// 01-May-2016, tatu: [databind#1217]: Remove properties from mapping,
377396
// to avoid them being deserialized
378-
_beanProperties = src._beanProperties.withoutProperties(ignorableProps);
397+
_beanProperties = src._beanProperties.withoutProperties(ignorableProps, includableProps);
379398
}
380399

400+
381401
/**
382402
* @since 2.8
383403
*/
@@ -394,6 +414,7 @@ protected BeanDeserializerBase(BeanDeserializerBase src, BeanPropertyMap beanPro
394414
_backRefs = src._backRefs;
395415
_ignorableProps = src._ignorableProps;
396416
_ignoreAllUnknown = src._ignoreAllUnknown;
417+
_includableProps = src._includableProps;
397418
_anySetter = src._anySetter;
398419
_injectables = src._injectables;
399420
_objectIdReader = src._objectIdReader;
@@ -411,7 +432,21 @@ protected BeanDeserializerBase(BeanDeserializerBase src, BeanPropertyMap beanPro
411432

412433
public abstract BeanDeserializerBase withObjectIdReader(ObjectIdReader oir);
413434

414-
public abstract BeanDeserializerBase withIgnorableProperties(Set<String> ignorableProps);
435+
public BeanDeserializerBase withIgnorableProperties(Set<String> ignorableProps) {
436+
return withIgnorableProperties(ignorableProps, _includableProps);
437+
}
438+
439+
/**
440+
* @since 2.12
441+
*/
442+
public abstract BeanDeserializerBase withIgnorableProperties(Set<String> ignorableProps, Set<String> includableProps);
443+
444+
/**
445+
* @since 2.12
446+
*/
447+
public BeanDeserializerBase withIncludableProperties(Set<String> includableProperties) {
448+
return withIgnorableProperties(_ignorableProps, includableProperties);
449+
}
415450

416451
// NOTE! To be made `abstract` in 2.12 or later
417452
/**
@@ -422,7 +457,7 @@ public BeanDeserializerBase withIgnoreAllUnknown(boolean ignoreUnknown) {
422457
if (ignoreUnknown == _ignoreAllUnknown) {
423458
return this;
424459
}
425-
return withIgnorableProperties(_ignorableProps);
460+
return withIgnorableProperties(_ignorableProps, _includableProps);
426461
}
427462

428463
/**
@@ -469,10 +504,10 @@ public void resolve(DeserializationContext ctxt) throws JsonMappingException
469504
// 22-Jan-2018, tatu: May need to propagate "ignorable" status (from `Access.READ_ONLY`
470505
// or perhaps class-ignorables) into Creator properties too. Can not just delete,
471506
// at this point, but is needed for further processing down the line
472-
if (_ignorableProps != null) {
507+
if (_ignorableProps != null || _includableProps != null) {
473508
for (int i = 0, end = creatorProps.length; i < end; ++i) {
474509
SettableBeanProperty prop = creatorProps[i];
475-
if (_ignorableProps.contains(prop.getName())) {
510+
if (IgnorePropertiesUtil.shouldIgnore(prop.getName(), _ignorableProps, _includableProps)) {
476511
creatorProps[i].markAsIgnorable();
477512
}
478513
}
@@ -773,6 +808,21 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
773808
contextual = contextual.withIgnoreAllUnknown(true);
774809
}
775810
}
811+
JsonIncludeProperties.Value inclusions = intr.findPropertyInclusions(accessor);
812+
if (inclusions != null) {
813+
Set<String> included = inclusions.getIncluded();
814+
Set<String> prev = contextual._includableProps;
815+
if (prev != null && included != null) {
816+
Set<String> newIncluded = new HashSet<>();
817+
// Make the intersection with the previously included properties.
818+
for(String prop : prev) {
819+
if (included.contains(prop)) {
820+
newIncluded.add(prop);
821+
}
822+
}
823+
contextual = contextual.withIncludableProperties(newIncluded);
824+
}
825+
}
776826
}
777827

778828
// One more thing: are we asked to serialize POJO as array?
@@ -1601,7 +1651,8 @@ protected void handleUnknownVanilla(JsonParser p, DeserializationContext ctxt,
16011651
Object beanOrBuilder, String propName)
16021652
throws IOException
16031653
{
1604-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
1654+
1655+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
16051656
handleIgnoredProperty(p, ctxt, beanOrBuilder, propName);
16061657
} else if (_anySetter != null) {
16071658
try {
@@ -1629,7 +1680,7 @@ protected void handleUnknownProperty(JsonParser p, DeserializationContext ctxt,
16291680
p.skipChildren();
16301681
return;
16311682
}
1632-
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
1683+
if (IgnorePropertiesUtil.shouldIgnore(propName, _ignorableProps, _includableProps)) {
16331684
handleIgnoredProperty(p, ctxt, beanOrClass, propName);
16341685
}
16351686
// Otherwise use default handling (call handler(s); if not

0 commit comments

Comments
 (0)