FasterXML / FasterXML/jackson-databind

Vanilla `BeanDeserializer` fast path never used with default settings in 3.x (due to `MapperFeature.DEFAULT_VIEW_INCLUSION` default change)

Open
#6,219 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
3.7k
Forks
1.5k
Avg merge
3d 6h
Merged PRs (30d)
28

Description

(filed via Claude Code)

### Describe the bug

In 3.x, the optimized "vanilla" processing of `BeanDeserializer` (`_vanillaDeserialize()`) is never used with default mapper settings -- even for plain POJOs with no `@JsonView` annotations, no injectables, no Object Id and default constructor.

Cause is `BeanDeserializerBuilder._anyViews()`:

```java
protected boolean _anyViews(Collection props)
{
// view processing must be enabled if:
// (a) fields are not included by default (when deserializing with view), OR
// (b) one of properties has view(s) to included in defined
if (!_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
return true;
}
...
```

With `DEFAULT_VIEW_INCLUSION` disabled, every bean deserializer gets `_needViewProcesing = true`, and since `BeanDeserializerBase` computes

```java
_vanillaProcessing = !_nonStandardCreation
&& (_injectables == null)
&& !_needViewProcesing
&& (_objectIdReader == null);
```

`_vanillaProcessing` is always `false`. This logic predates 3.0, when the feature was enabled by default; but #1484 (via #4885) changed the default of `DEFAULT_VIEW_INCLUSION` to `false` for 3.0, so now all POJOs take the non-vanilla `deserializeFromObject()` path regardless of whether views are used at all.

Consequences:

- Default configuration never uses the vanilla fast path, including improvements to it like #6193 (measured about +10% throughput for `byte[]` input -- but only with `DEFAULT_VIEW_INCLUSION` explicitly enabled).
- Afterburner (`SuperSonicBeanDeserializer`, `SuperSonicUnrolledDeserializer`) and Blackbird (`SuperSonicBeanDeserializer`) check `_vanillaProcessing` and fall back to `super.deserialize()` when it is `false`, so their optimized deserialization appears to be bypassed with default settings as well.

### Version Information

3.0.0 and later

### Reproduction

For a plain POJO like

```java
static class Point {
public int x, y;
}
```

inspecting the root `BeanDeserializer` (e.g. via `DeserializationContext.findRootValueDeserializer()`):

- default `JsonMapper`: `_needViewProcesing = true`, `_vanillaProcessing = false`
- `JsonMapper.builder().enable(MapperFeature.DEFAULT_VIEW_INCLUSION).build()`: `_needViewProcesing = false`, `_vanillaProcessing = true`

(`BeanDeserializerVanillaTest` added by #6193 has to enable `DEFAULT_VIEW_INCLUSION` explicitly to get vanilla processing.)

### Expected behavior

Vanilla processing should be usable whenever no view is active during deserialization (and no other non-vanilla conditions apply). Views only matter if a view is active, and that is already checked at runtime in non-vanilla paths, e.g. `BeanDeserializer`:

```java
if (_needViewProcesing) {
Class view = ctxt.getActiveView();
if (view != null) {
return deserializeWithView(p, ctxt, bean, view);
}
}
```

Possible approach: stop folding `_needViewProcesing` into `_vanillaProcessing` at construction time, and instead check `!_needViewProcesing || ctxt.getActiveView() == null` at the points where vanilla processing is chosen:

- `BeanDeserializerBase` (flag computation and copy constructors)
- `BeanDeserializer.deserialize()` / `_deserializeOther()`
- `BuilderBasedDeserializer`
- `BeanAsArrayDeserializer` / `BeanAsArrayBuilderDeserializer`
- Afterburner / Blackbird `SuperSonic*` deserializers (jackson-modules-base)

(Note that simply changing `_anyViews()` would not be correct: with `DEFAULT_VIEW_INCLUSION` disabled, an active view excludes un-annotated properties, so view processing is needed whenever a view is active.)

### Additional context

Found while reviewing #6193. Performance difference between vanilla and non-vanilla paths themselves has not yet been measured.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with BeanDeserializerBase and the vanilla-selection logic in BeanDeserializer.deserialize() and _deserializeOther(), then inspect the corresponding BuilderBasedDeserializer and BeanAsArrayDeserializer paths. Review BeanDeserializerVanillaTest and the named Afterburner and Blackbird SuperSonic* deserializers. Done means plain POJOs use vanilla processing by default when no view is active, while active views still use view processing.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.