Skip to content

Fix #6144: withCreatorVisibility(ANY) now enables private scalar delegating constructors - #6152

Open
seonwooj0810 wants to merge 1 commit into
FasterXML:3.xfrom
seonwooj0810:fix/6144-creator-visibility-scalar-ctor
Open

Fix #6144: withCreatorVisibility(ANY) now enables private scalar delegating constructors#6152
seonwooj0810 wants to merge 1 commit into
FasterXML:3.xfrom
seonwooj0810:fix/6144-creator-visibility-scalar-ctor

Conversation

@seonwooj0810

Copy link
Copy Markdown
Contributor

Problem

FasterXML/jackson-databind#6144

In Jackson 3, implicit single-arg (scalar) constructors (String, long, etc.) used as
delegating creators go through _removeNonVisibleCreators, which checks
isScalarConstructorVisible against the new scalarConstructorMinLevel axis (defaulting to
NON_PRIVATE).

When users migrate from Jackson 2 — where creator visibility defaulted to ANY — the natural
fix attempt is changeDefaultVisibility(vc -> vc.withCreatorVisibility(Visibility.ANY)).
This has no effect on scalar constructors because withCreatorVisibility does not touch
_scalarConstructorMinLevel, leaving private scalar constructors still filtered out.

Repro

static class OneOf {
    public long longValue;
    public String stringValue;
    public OneOf() {}
    private OneOf(long v)   { this.longValue = v; }
    private OneOf(String v) { this.stringValue = v; }
}

// Works in Jackson 2, fails in Jackson 3 with default settings:
ObjectMapper mapper = JsonMapper.builder()
    .changeDefaultVisibility(vc -> vc.withCreatorVisibility(Visibility.ANY))
    .build();

OneOf fromLong = mapper.readValue("42", OneOf.class); // MismatchedInputException

Fix

In POJOPropertiesCollector._removeNonVisibleCreators, for single-arg constructors, accept when
either isScalarConstructorVisible or isCreatorVisible passes:

visible = _visibilityChecker.isScalarConstructorVisible(ctor.creator())
        || _visibilityChecker.isCreatorVisible(ctor.creator());

This means:

  • Default behaviour unchanged: both isScalarConstructorVisible (NON_PRIVATE) and
    isCreatorVisible (PUBLIC_ONLY) return false for private constructors — they are still
    filtered out.
  • withCreatorVisibility(ANY) now works: isCreatorVisible returns true for private
    constructors, so they are kept — restoring Jackson 2 migration behaviour.
  • withScalarConstructorVisibility(ANY) continues to work as before.

Tests

Added testPrivateLongDelegatingCtorWithCreatorVisibilityAny to TestAutoDetect:

  • Verifies that with default settings, private scalar constructors are still filtered (no
    regression).
  • Verifies that with withCreatorVisibility(ANY), both private long and private String
    constructors work as implicit delegating creators.

All existing TestAutoDetect tests pass.

Note: This fix was authored with the assistance of Claude AI (Anthropic).

…alar delegating constructors

In Jackson 3, `_removeNonVisibleCreators` used only `isScalarConstructorVisible`
(which checks the new `scalarConstructorMinLevel`, defaulting to NON_PRIVATE) for
single-arg constructors. This meant that setting `withCreatorVisibility(Visibility.ANY)` —
the natural Jackson 2→3 migration step — had no effect on implicit private scalar
(long/String) constructors.

Fix: for single-arg constructors, accept when EITHER `isScalarConstructorVisible`
OR `isCreatorVisible` passes, so that `withCreatorVisibility(ANY)` restores the
Jackson 2 behaviour where private scalar constructors were accepted implicitly.

Default behaviour (NON_PRIVATE scalar + PUBLIC_ONLY creator) is unchanged because
both conditions return false for private constructors under those defaults.
@cowtowncoder

cowtowncoder commented Aug 12, 2026

Copy link
Copy Markdown
Member

I am not sure this is correct -- Scalar creator visibility check should be used in 3.x, not general-purpose one (unlike in 2.x).

That is: VisibilityChecker.withScalarConstructorVisibility() is to be used with scalar-delegating constructors

Will add a note on #6144.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants