Skip to content

MapperFeature.DETECT_PARAMETER_NAMES=false silently disables @ConstructorProperties-based Creator detection too #6229

Description

@mauriciocsz

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

MapperFeature.DETECT_PARAMETER_NAMES was added in #5314 as an opt-out for the Jackson-3-only behavior where constructor/factory-method parameter names are inferred from compiled -parameters bytecode (previously the separate jackson-parameter-names module in Jackson 2).

Disabling this feature also silently disables implicit-name resolution via @ConstructorProperties, an older and completely independent JavaBeans mechanism that has nothing to do with -parameters bytecode metadata. This worked fine in Jackson 2 regardless of whether jackson-parameter-names was registered.

The cause is in JacksonAnnotationIntrospector.findImplicitPropertyName():
the DETECT_PARAMETER_NAMES check is a single early-return placed before the method checks for @ConstructorProperties, so disabling the flag also kills the annotation-based path, not just the bytecode-based one:

public String findImplicitPropertyName(MapperConfig<?> config, AnnotatedMember m)
{
    // 15-Sep-2025: As per [databind#5314] possible to disable introspection
    if (!config.isEnabled(MapperFeature.DETECT_PARAMETER_NAMES)) {
        return null;   // <-- returns before ever checking @ConstructorProperties
    }
    if (m instanceof AnnotatedParameter p) {
        AnnotatedWithParams owner = p.getOwner();
        if (owner instanceof AnnotatedConstructor) {
            if (_javaBeansHelper != null) {
                PropertyName name = _javaBeansHelper.findConstructorName(p);  // @ConstructorProperties
                ...
            }
            return _findImplicitName(owner, p.getIndex());  // -parameters bytecode
        }
        ...

This affects any class using @ConstructorProperties — notably Lombok output when lombok.anyConstructor.addConstructorProperties=true is set — as soon as a consumer disables DETECT_PARAMETER_NAMES for any reason (e.g. Jackson 2 behavior parity, or avoiding reliance on -parameters compilation).

Version Information

3.x (3.3.0-SNAPSHOT, current 3.x branch HEAD)

Reproduction

import java.beans.ConstructorProperties;
import tools.jackson.databind.MapperFeature;
import tools.jackson.databind.json.JsonMapper;

public class Repro {
    static class CtorPropsDto {
        public final int id;
        public final String name;

        @ConstructorProperties({"id", "name"})
        public CtorPropsDto(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    public static void main(String[] args) {
        JsonMapper mapper = JsonMapper.builder()
                .disable(MapperFeature.DETECT_PARAMETER_NAMES)
                .build();
        // throws InvalidDefinitionException: "... has no property name
        // (and is not Injectable): cannot use as property-based Creator"
        mapper.readValue("{\"id\":1,\"name\":\"x\"}", CtorPropsDto.class);
    }
}

Expected behavior

@ConstructorProperties-annotated constructors should keep resolving implicit parameter names regardless of DETECT_PARAMETER_NAMES, since that flag's documented purpose (see its Javadoc and the original request in #5314) is
scoped to the bytecode/-parameters behavior merged from the old jackson-parameter-names module, not to @ConstructorProperties, which predates and is independent of it.

Additional context

I have a minimal, scoped fix ready (moves the DETECT_PARAMETER_NAMES check to only guard the bytecode-based fallback branch, leaving the @ConstructorProperties branch unconditional) plus regression tests covering:

  • @ConstructorProperties still works with the flag enabled (baseline, unchanged)
  • @ConstructorProperties now works with the flag disabled (the fix)
  • a bytecode-only constructor (no @ConstructorProperties) is still correctly
    suppressed when the flag is disabled (guard rail against over-fixing)

The fix is contained here: #6230

Let me know if I can provide anything else to help this move forward! 😄

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions