Skip to content

findImplicitPropertyName and setPropertyNamingStrategy change from 2.6.4 to 2.7.0 #1077

@michaelhixson

Description

@michaelhixson

I use a custom AnnotationIntrospector that reads the java.beans.ConstructorProperties annotation on constructors. It figures out the mapping from JSON fields to constructor arguments. This code worked in 2.6.4 but broke in 2.7.0, with respect to its interaction with PropertyNamingStrategy.

Here's a sample unit test that used to pass but now fails:

@Test
public void testConstructorProperties() throws IOException {
  Assert.assertEquals(
      "{\"first_value\":7,\"second_value\":9}",
      new ObjectMapper()
          .registerModule(new ConstructorPropertiesModule())
          .setPropertyNamingStrategy(
              PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES)
          .writeValueAsString(new Foo(7, 9)));
}

public static final class Foo {
  private final Integer firstValue;
  private final Integer secondValue;

  @java.beans.ConstructorProperties({"firstValue", "secondValue"})
  public Foo(Integer firstValue, Integer secondValue) {
    this.firstValue = firstValue;
    this.secondValue = secondValue;
  }

  public Integer getFirstValue() {
    return firstValue;
  }

  public Integer getSecondValue() {
    return secondValue;
  }
}

public static final class ConstructorPropertiesModule extends SimpleModule {
  @Override
  public void setupModule(SetupContext context) {
    super.setupModule(context);
    context.insertAnnotationIntrospector(new NopAnnotationIntrospector() {
      @Override
      public boolean hasCreatorAnnotation(Annotated a) {
        return a instanceof AnnotatedConstructor
            && a.hasAnnotation(ConstructorProperties.class);
      }

      @Override
      public String findImplicitPropertyName(AnnotatedMember member) {
        if (!(member instanceof AnnotatedParameter)) {
          return null;
        }
        AnnotatedParameter parameter = (AnnotatedParameter) member;
        AnnotatedWithParams owner = parameter.getOwner();
        if (!(owner instanceof AnnotatedConstructor)) {
          return null;
        }
        AnnotatedConstructor constructor = (AnnotatedConstructor) owner;
        ConstructorProperties properties =
            constructor.getAnnotation(ConstructorProperties.class);
        if (properties == null) {
          return null;
        }
        int index = parameter.getIndex();
        String[] parameterNames = properties.value();
        if (index < 0 || index >= parameterNames.length) {
          return null;
        }
        return parameterNames[index];
      }
    });
  }
}

In case it matters, the use case for that custom AnnotationIntrospector is enabling deserialization of Lombok @Value classes. https://projectlombok.org/features/Value.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions