preface

We recently encountered an abnormal polymorphic serialization problem in our company’s project. Details are as follows:

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.x.x.x.Payment]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.x.x.x.Payment` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

Copy the code

The project requires users to add their own Payment methods, which are divided into ABC and inherit the Payment class. The interface code is as follows:

	// Request URL and type are hidden
    @ApiOperation("Add payment method")
    public ResultInfo<? extends Payment> createPayment(
            @RequestBody Payment req) {

        return ResultInfo.success(xx.createPayment(req));
    }
Copy the code

Solutions are as follows:

// Add this information to the Payment class
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "payment"
)
@JsonSubTypes(value = {
        @JsonSubTypes.Type(value = A.class, name = "A"),
        @JsonSubTypes.Type(value = B.class, name = "B"),
        @JsonSubTypes.Type(value = C.class, name = "C")})public class Payment {
// I will not write the specific field

}
Copy the code

Available online

  • @JsonTypeInfo– Indicates the details of what type information to include in serialization
  • @JsonSubTypes— Indicates subtypes of the annotated type
  • @JsonTypeName– Defines a logical type name to use for annotated class

In the above data, the most critical annotation addressing polymorphism is @jsonTypeInfo

  • Use: What is used to distinguish between different types in serialization and the type converted to the response in deserialization

    • JsonTypeInfo.Id.CLASS: Use fully qualified class names for identification
    • JsonTypeInfo.Id.MINIMAL_CLASS: If the parent class and subclass are in the same package class, use the class name (ignoring the package name) as the identification number
    • JsonTypeInfo.Id.NAME: a logical designation
    • JsonTypeInfo.Id.NONE: Do not use an identifier
  • Include (optional) : A mechanism for including type metadata, specifying how the identifier is included, with the following optional values:

    • JsonTypeInfo.As.PROPERTY: as the sibling of the data
    • JsonTypeInfo.As.EXISTING_PROPERTY: as an existing property in the POJO
    • JsonTypeInfo.As.EXTERNAL_PROPERTY: as an extended attribute
    • JsonTypeInfo.As.WRAPPER_OBJECT: as a wrapped object
    • JsonTypeInfo.As.WRAPPER_ARRAY: as a wrapped array
  • Property (Optional) : Indicates the id of a user-defined type. The default value is @Class. This property can be used only when:

    • useforJsonTypeInfo.Id.CLASS(default @class if property is not specified),JsonTypeInfo.Id.MINIMAL_CLASS(default @class if property is not specified),JsonTypeInfo.Id.NAME(default @type if property is not specified),
    • includeforJsonTypeInfo.As.PROPERTY,JsonTypeInfo.As.EXISTING_PROPERTY,JsonTypeInfo.As.EXTERNAL_PROPERTYOnly when effective
  • DefaultImpl (Optional) : If the type identifier does not exist or is invalid, you can use this property to specify the default type to use for deserialization

  • Visible (Optional) : Visible (default false) The property defines whether the value of the type identifier will become part of the deserializer through the JSON stream. The default is fale, which means Jackson will process and remove the type identifier from the JSON content and pass it to JsonDeserializer


@JsonSubTypes

Class/interface to list the subclasses of a given class, used only when the subclass type cannot be detected, typically in conjunction with @jsonTypeInfo on the base class. The value of @jsonSubtypes is an @JsonSubtypes.type [] array that enumerates polymorphic types (value for subclasses) and Type identifier values (name for the property identifier name in @JsonTypeInfo, which is optional, @jsonTypename on a subclass if not specified.

Come back for more when you have a chance

  • Article Reference: