WRAPPER_ARRAY And RequireTypeIdForSubtypes Don't Work Together

by ADMIN 63 views

Introduction

In this article, we will explore a bug in the Jackson library, specifically when using the WRAPPER_ARRAY type information and the requireTypeIdForSubtypes feature together. We will examine the issue, provide a test case, and discuss the expected behavior.

Search before asking

Before diving into the issue, it's essential to follow the best practices for debugging and troubleshooting. In this case, we have searched the Jackson issues repository and found nothing similar to this problem.

Describe the bug

The test case below demonstrates the issue:

@Test
void test() throws JsonProcessingException {
    System.out.println(jacksonObjectMapper.readValue("""
            {"s": "ABC"}
            """, SealedRecords.A.class));
}

The SealedRecords interface is annotated with @JsonTypeInfo to specify the type information for the sealed records. The use parameter is set to JsonTypeInfo.Id.SIMPLE_NAME, and the include parameter is set to JsonTypeInfo.As.WRAPPER_ARRAY. Additionally, the requireTypeIdForSubtypes parameter is set to OptBoolean.FALSE.

However, when running the test, it fails with the following error:

Unexpected token (START_OBJECT), expected START_ARRAY: need Array value to contain `As.WRAPPER_ARRAY` type information ...

This error indicates that the Jackson library is expecting an array value to contain the type information, but instead, it receives an object value.

Version Information

The version of the Jackson library used in this test case is 2.17.2.

Reproduction

To reproduce the issue, you can use the following code:

@JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, include = JsonTypeInfo.As.WRAPPER_ARRAY, requireTypeIdForSubtypes = OptBoolean.FALSE)
sealed interface SealedRecords {
    record A(String s) implements SealedRecords {}
}

Expected behavior

The expected behavior is that the Jackson library should be able to deserialize the JSON string into an instance of the SealedRecords.A class without any issues.

Additional context

The requireTypeIdForSubtypes feature is used to specify whether the type information is required for subtypes. In this case, it is set to OptBoolean.FALSE, which means that the type information is not required for subtypes.

However, when using the WRAPPER_ARRAY type information, the Jackson library expects the type information to be present in the array value. Since the requireTypeIdForSubtypes feature is set to OptBoolean.FALSE, the type information is not present in the array value, leading to the error.

Conclusion

In conclusion, the issue arises from the combination of using the WRAPPER_ARRAY type information and the requireTypeIdForSubtypes feature together. The Jackson library expects the type information to be present in the array value when using WRAPPER_ARRAY, but since the requireTypeIdForSubtypes feature is set to OptBoolean.FALSE, the type information is not present, leading to the error.

Workaround

A workaround for this issue is to switch to using the PROPERTY type information instead of WRAPPER_ARRAY. This can be done by changing the include parameter in the @JsonTypeInfo annotation to JsonTypeInfo.As.PROPERTY.

@JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, include = JsonTypeInfo.As.PROPERTY, requireTypeIdForSubtypes = OptBoolean.FALSE)
sealed interface SealedRecords {
    record A(String s) implements SealedRecords {}
}

Q: What is the issue with using WRAPPER_ARRAY and requireTypeIdForSubtypes together?

A: The issue arises from the combination of using the WRAPPER_ARRAY type information and the requireTypeIdForSubtypes feature together. The Jackson library expects the type information to be present in the array value when using WRAPPER_ARRAY, but since the requireTypeIdForSubtypes feature is set to OptBoolean.FALSE, the type information is not present, leading to the error.

Q: What is the expected behavior when using WRAPPER_ARRAY and requireTypeIdForSubtypes together?

A: The expected behavior is that the Jackson library should be able to deserialize the JSON string into an instance of the sealed record class without any issues.

Q: What is the workaround for this issue?

A: A workaround for this issue is to switch to using the PROPERTY type information instead of WRAPPER_ARRAY. This can be done by changing the include parameter in the @JsonTypeInfo annotation to JsonTypeInfo.As.PROPERTY.

Q: Why is the requireTypeIdForSubtypes feature not working as expected?

A: The requireTypeIdForSubtypes feature is not working as expected because it is set to OptBoolean.FALSE, which means that the type information is not required for subtypes. However, when using WRAPPER_ARRAY, the Jackson library expects the type information to be present in the array value.

Q: Can I use both WRAPPER_ARRAY and requireTypeIdForSubtypes together?

A: Unfortunately, no. The combination of using WRAPPER_ARRAY and requireTypeIdForSubtypes together is not supported by the Jackson library.

Q: What are the implications of this issue?

A: The implications of this issue are that developers who are using sealed records with WRAPPER_ARRAY type information and requireTypeIdForSubtypes feature may encounter errors when deserializing JSON strings. This may require developers to switch to using PROPERTY type information instead.

Q: Is this issue specific to sealed records?

A: No, this issue is not specific to sealed records. It can occur with any type of class that uses WRAPPER_ARRAY type information and requireTypeIdForSubtypes feature.

Q: Can I report this issue to the Jackson library developers?

A: Yes, you can report this issue to the Jackson library developers. They may be able to provide a fix or a workaround for this issue.

Q: What is the current status of this issue?

A: The current status of this issue is that it is a known bug in the Jackson library. The developers are aware of the issue and may be working on a fix or a workaround.

Q: When can I expect a fix for this issue?

A: Unfortunately, it is difficult to predict when a fix for this issue will be available. The Jackson library developers may need to prioritize other issues or features before addressing this bug.