Skip to content

Jackson auto configuration error causes Spring Messaging MappingJackson2MessageConverter conversion failure #42609

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cooperlyt opened this issue Oct 14, 2024 · 9 comments
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid

Comments

@cooperlyt
Copy link

cooperlyt commented Oct 14, 2024

There are some issues with the ObjectMapper generated by the default configuration in the Spring context. When using the readerWithView() method to deserialize objects, it results in an error (all properties of the generated object are null). This directly affects Spring Messaging because MappingJackson2MessageConverter uses this method for deserialization, causing failures in Spring Messaging. However, when I use an ObjectMapper created with Jackson's default configuration, the issue does not occur. I created a Test project kotlin , java to verify this, and below is the simplified code for the test:

Different:
Spring ObjectMapper: MapperFeature.DEFAULT_VIEW_INCLUSION is false
Default ObjectMapper: MapperFeature.DEFAULT_VIEW_INCLUSION is true
I don't know this a wrong configuration or Jackson's bug!

Spring boot version is 3.3.4

@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = Main.class)
public class JsonTest {

  static class SimpleStockFreezeStatusMessage {

    private Long businessId;
    private Boolean success;
    private String tenantId;

   // getter and setter  ...
  }

  public void testSpringJsonMessage(ObjectMapper objectMapper) throws IOException {
    var json = "{\"businessId\":1336504106360835,\"tenantId\":\"first\",\"success\":false}";
    var value = objectMapper.readValue(json, SimpleStockFreezeStatusMessage.class);
    System.out.println("message ser by readValue : " + value.tenantId);

    // success
    assertEquals(value.tenantId, "first");

    Class<?> view = SimpleStockFreezeStatusMessage.class;
    JavaType javaType = objectMapper.constructType(new  TypeReference<SimpleStockFreezeStatusMessage>() {});

    //this is Spring message Usage
    var value2 = (SimpleStockFreezeStatusMessage)objectMapper.readerWithView(view).forType(javaType).readValue(json);
    System.out.println("message ser by readerWithView: " + value2.tenantId);

    // tenantId is null
    assertEquals(value2.tenantId, "first");
  }

  @Autowired
  private  ObjectMapper objectMapper;

  //Fails
  @Test
  public void testBySpringMapper() throws IOException {
    testSpringJsonMessage(objectMapper);
  }
  
    //Success
  @Test
  public void testByDefaultMapper() throws IOException {
    testSpringJsonMessage(new ObjectMapper());
  }
}

The same issue also exists in version 3.2.9

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 14, 2024
@quaff
Copy link
Contributor

quaff commented Oct 14, 2024

Different:
Spring ObjectMapper: MapperFeature.DEFAULT_VIEW_INCLUSION is false
Default ObjectMapper: MapperFeature.DEFAULT_VIEW_INCLUSION is true
I don't know this a wrong configuration or Jackson's bug!

Spring Framework set DEFAULT_VIEW_INCLUSION to false by default.

https://github.com/spring-projects/spring-framework/blob/b3cc9a219e79cd7c99c528229be502f55fa9c97b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java#L814

You can enable it by configuration properties:

spring.jackson.mapper.default-view-inclusion: true

@cooperlyt
Copy link
Author

cooperlyt commented Oct 14, 2024

Different:
Spring ObjectMapper: MapperFeature.DEFAULT_VIEW_INCLUSION is false
Default ObjectMapper: MapperFeature.DEFAULT_VIEW_INCLUSION is true
I don't know this a wrong configuration or Jackson's bug!

Spring Framework set DEFAULT_VIEW_INCLUSION to false by default.

https://github.com/spring-projects/spring-framework/blob/b3cc9a219e79cd7c99c528229be502f55fa9c97b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java#L814

You can enable it by configuration properties:

spring.jackson.mapper.default-view-inclusion: true

I believe that unless there's a specific reason, Spring Boot should set the default value of DEFAULT_VIEW_INCLUSION to true. When it is set to false, the org.springframework.messaging.converter.MappingJackson2MessageConverter will fail. It took me two days of debugging to find this configuration, and it posed an obstacle for using Spring Messaging.
However, setting spring.jackson.mapper.default-view-inclusion: true has solved my problem.
Thanks

@mdeinum
Copy link
Contributor

mdeinum commented Oct 14, 2024

There is a specific reason, which can be found here (in a migrated issue from 2014).

@wilkinsona
Copy link
Member

wilkinsona commented Oct 14, 2024

Thanks for the report, but as explained above, Spring Boot is just picking up Spring Framework's default configuration and we don't want to override that as it is false for good reason. If you disagree with this default in Spring Framework, you may want to open a Spring Framework issue.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Oct 14, 2024
@wilkinsona wilkinsona added status: invalid An issue that we don't feel is valid for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 14, 2024
@cooperlyt
Copy link
Author

Oh, that sounds reasonable. We should expect Jackson-databind's readerWithView() method to work even when DEFAULT_VIEW_INCLUSION is set to false. I believe this is a bug in Jackson-databind.
Thanks for all!

@quaff
Copy link
Contributor

quaff commented Oct 14, 2024

Oh, that sounds reasonable. We should expect Jackson-databind's readerWithView() method to work even when DEFAULT_VIEW_INCLUSION is set to false. I believe this is a bug in Jackson-databind. Thanks for all!

It's designed feature, why do you think it's a bug of jackson-databind?

@cooperlyt
Copy link
Author

cooperlyt commented Oct 14, 2024

Oh, that sounds reasonable. We should expect Jackson-databind's readerWithView() method to work even when DEFAULT_VIEW_INCLUSION is set to false. I believe this is a bug in Jackson-databind. Thanks for all!

It's designed feature, why do you think it's a bug of jackson-databind?

    Class<?> view = SimpleStockFreezeStatusMessage.class;
    JavaType javaType = objectMapper.constructType(new  TypeReference<SimpleStockFreezeStatusMessage>() {});

    //this is Spring message Usage
    var value2 = (SimpleStockFreezeStatusMessage)objectMapper.readerWithView(view).forType(javaType).readValue(json);
    System.out.println("message ser by readerWithView: " + value2.tenantId);

    //fail tenantId is null
    assertEquals(value2.tenantId, "first");

In this code, I have explicitly specified the "View", so even with DEFAULT_VIEW_INCLUSION set to false, it should successfully return the object. However, right now, the returned object has all its properties as null. Isn't this a bug?

And this is exactly how org.springframework.messaging.converter.MappingJackson2MessageConverter is implemented!

@cooperlyt
Copy link
Author

Oh, that sounds reasonable. We should expect Jackson-databind's readerWithView() method to work even when DEFAULT_VIEW_INCLUSION is set to false. I believe this is a bug in Jackson-databind. Thanks for all!

It's designed feature, why do you think it's a bug of jackson-databind?

You're right, I made a mistake; I misunderstood readerWithView(),This is indeed not a bug, but it's still quite puzzling that Spring Messaging doesn't work correctly by default. It's especially challenging when using Java instead of Kotlin, as there are no null checks, and without any exceptions being thrown, it makes troubleshooting much more difficult.

@quaff
Copy link
Contributor

quaff commented Oct 15, 2024

 Class<?> view = SimpleStockFreezeStatusMessage.class;

I think you misunderstood @JsonView, SimpleStockFreezeStatusMessage seems not like a view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

5 participants