Skip to content

Commit aef5da9

Browse files
authored
Major refactoring of property (name) ignorals (#5954)
1 parent 4fba494 commit aef5da9

5 files changed

Lines changed: 307 additions & 91 deletions

File tree

‎src/main/java/tools/jackson/databind/BeanDescription.java‎

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,33 +99,47 @@ public boolean isNonStaticInnerClass() {
9999
public abstract List<BeanPropertyDefinition> findProperties();
100100

101101
/**
102-
* Returns the set of property names that are marked to be ignored, from both
103-
* per-property {@code @JsonIgnore} markers and class-level
104-
* {@code @JsonIgnoreProperties} (annotation and config overrides).
105-
* The set is direction-specific: a name may appear for serialization but not
102+
* Returns the full set of property names marked ignored — combining per-property
103+
* {@code @JsonIgnore} markers, class-level {@code @JsonIgnoreProperties}
104+
* (annotation and config overrides), and read/write-only access rules. The set
105+
* is direction-specific: a name may appear for serialization but not
106106
* deserialization, depending on the annotation attributes.
107107
*<p>
108-
* <b>Caveat for factory layers:</b> this set is <em>not</em> a complete runtime
109-
* ignore-list. Names that collide with a creator parameter may have been
110-
* removed during property renaming (see {@code [databind#2001]} /
111-
* {@code [databind#2118]} handling in {@code POJOPropertiesCollector}). When
112-
* building a deserializer's ignorable-property set, factories must therefore
113-
* combine this with {@link #getPropertyIgnorals()}'s direction-specific names
114-
* to get the full effective set. See
115-
* {@code BeanDeserializerFactory#addBeanProps} for the canonical pattern.
108+
* Per-property names that have been "rescued" by a creator parameter renamed
109+
* to the same name (see {@code [databind#2001]}) are excluded; class-level
110+
* names are absolute and always appear. This is the canonical accessor for
111+
* building a deserializer's runtime ignore-list — factory code does not need
112+
* to combine it with {@link #getPropertyIgnorals()}.
116113
*/
117114
public abstract Set<String> getIgnoredPropertyNames();
118115

116+
/**
117+
* Returns the un-rescued view of {@link #getIgnoredPropertyNames()}: includes
118+
* per-property names that {@code [databind#2001]} would later rescue when a
119+
* creator parameter is renamed to the same name. Class-level names are
120+
* included exactly as in the rescued view (they are absolute either way).
121+
*<p>
122+
* Default implementation returns {@link #getIgnoredPropertyNames()}; subclasses
123+
* backed by a property collector override to return the un-rescued set. Most
124+
* callers should use {@link #getIgnoredPropertyNames()}; this exists for
125+
* tooling that needs to inspect the original ignoral declarations.
126+
*
127+
* @since 3.2
128+
*/
129+
public Set<String> getNonRescuedIgnoredPropertyNames() {
130+
return getIgnoredPropertyNames();
131+
}
132+
119133
/**
120134
* Returns the class-level property ignorals value (annotation plus config overrides),
121135
* pre-computed during property collection. Preferred over re-calling
122136
* {@code findPropertyIgnoralByName()} in factory code since the result is cached.
123137
* Returns {@code null} when neither annotation nor config override defines any ignorals.
124138
*<p>
125-
* Note: this only carries class-level ignorals. Per-property {@code @JsonIgnore}
126-
* names live in {@link #getIgnoredPropertyNames()} instead. Neither accessor on
127-
* its own is a complete runtime ignore-list — see the caveat on
128-
* {@link #getIgnoredPropertyNames()}.
139+
* Equivalent to the class-level subset of {@link #getIgnoredPropertyNames()}
140+
* but in {@link JsonIgnoreProperties.Value} form, which additionally carries
141+
* the {@code ignoreUnknown}, {@code allowGetters}, {@code allowSetters}, and
142+
* {@code merge} attributes.
129143
*/
130144
public JsonIgnoreProperties.Value getPropertyIgnorals() {
131145
return null;

‎src/main/java/tools/jackson/databind/deser/BeanDeserializerFactory.java‎

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -545,20 +545,13 @@ protected void addBeanProps(DeserializationContext ctxt,
545545
final boolean hasCreatorProps = (creatorProps != null);
546546

547547
// Class-level ignorals (annotation + config overrides): pre-computed during
548-
// property collection, so no second findPropertyIgnoralByName() call needed.
548+
// property collection. Surface the direction-specific name set so we can
549+
// pass it to filterBeanProps() and the ignoreUnknown flag to the builder.
549550
JsonIgnoreProperties.Value ignorals = beanDesc.getPropertyIgnorals();
550551
Set<String> ignored;
551552
if (ignorals != null) {
552553
builder.setIgnoreUnknownProperties(ignorals.getIgnoreUnknown());
553554
ignored = ignorals.findIgnoredForDeserialization();
554-
// NOTE: must register class-level ignorals here separately from the
555-
// per-property loop below: per [databind#2001]/[databind#2118], names
556-
// that collide with creator parameters get stripped out of
557-
// POJOPropertiesCollector#_ignoredPropertyNames during rename, so
558-
// beanDesc.getIgnoredPropertyNames() does NOT cover them.
559-
for (String propName : ignored) {
560-
builder.addIgnorable(propName);
561-
}
562555
} else {
563556
ignored = Collections.emptySet();
564557
}
@@ -580,17 +573,14 @@ protected void addBeanProps(DeserializationContext ctxt,
580573
if (anySetter != null) {
581574
builder.setAnySetter(anySetter);
582575
}
583-
// [databind#5952]: per-property @JsonIgnore (and read-only access rules) must
584-
// be registered as ignorable regardless of whether an any-setter exists, so
585-
// the any-setter does not receive properties the user explicitly marked as
586-
// ignored. (Class-level @JsonIgnoreProperties names are registered separately
587-
// above; this is needed because creator-prop renaming may remove class-level
588-
// names from POJOPropertiesCollector#_ignoredPropertyNames.)
589-
Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames();
590-
if (ignored2 != null) {
591-
for (String propName : ignored2) {
592-
builder.addIgnorable(propName);
593-
}
576+
// [databind#5952]: register the full deser-side ignore-list (per-property
577+
// @JsonIgnore, class-level @JsonIgnoreProperties, read-only access rules)
578+
// unconditionally, so the any-setter does not receive properties the user
579+
// explicitly marked as ignored. getIgnoredPropertyNames() returns the
580+
// already-merged set with the [databind#2001] creator-rename rescue
581+
// applied to per-property names only — class-level names remain absolute.
582+
for (String propName : beanDesc.getIgnoredPropertyNames()) {
583+
builder.addIgnorable(propName);
594584
}
595585
final boolean useGettersAsSetters = ctxt.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS);
596586
// 24-Sep-2017, tatu: Legacy setting removed from 3.x, not sure if other visibility checks

‎src/main/java/tools/jackson/databind/introspect/BasicBeanDescription.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ public Set<String> getIgnoredPropertyNames() {
247247
return ign;
248248
}
249249

250+
@Override
251+
public Set<String> getNonRescuedIgnoredPropertyNames() {
252+
return (_propCollector == null) ? Collections.emptySet()
253+
: _propCollector.getNonRescuedIgnoredPropertyNames();
254+
}
255+
250256
@Override
251257
public JsonIgnoreProperties.Value getPropertyIgnorals() {
252258
return (_propCollector == null) ? null

0 commit comments

Comments
 (0)