FasterXML / FasterXML/jackson-databind
Vanilla `BeanDeserializer` fast path never used with default settings in 3.x (due to `MapperFeature.DEFAULT_VIEW_INCLUSION` default change)
- 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