Search code examples
javaarraysjsonjacksonpolymorphic-deserialization

Jackson @JsonSubTypes - Polymorphic deserialization with generics


I'm trying to deserialize this json body that I don't have any control over. Because the API I'm calling could provide different "data" (arrays of objects) depending on the "method" value, I thought of polymorphism and using @JsonSubTypes. However the current set up gives me an error. I'm already using generics for another case which where "data" is an object and that works fine. But I'm not able to solve this with arrays of objects.

com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class demo.common.dto.response.data.AccountLedgerResponse

Not sure what it is referring to since "data" json property starts with "[".

JSON

{
    "version": "1.1",
    "result": {
        "signature": "lCteM8iCg++7uyF...TYoY/mc7eUQ6FWNPg==",
        "method": "AccountLedger",
        "data": [{
            "userid": "3839426635",
            "datestamp": "2014-01-30 13:28:45.652299+01",
            "orderid": "3209647863",
            "accountname": "SUSPENSE_ACCOUNT_CLIENT_FUNDS_SWEDEN_ESSE",
            "messageid": "133921",
            "transactiontype": "User deposit of client funds to CLIENT_FUNDS_SWEDEN_ESSE",
            "currency": "EUR",
            "amount": "5.00000000000000000000",
            "gluepayid": "3209647863"
        }, {
            "accountname": "TRANSACTION_FEE_BANK_DEPOSIT",
            "orderid": "3209647863",
            "userid": "3839426635",
            "datestamp": "2014-01-30 13:28:45.652299+01",
            "messageid": "133921",
            "transactiontype": "User deposit of client funds to CLIENT_FUNDS_SWEDEN_ESSE",
            "currency": "SEK",
            "amount": "-3.01",
            "gluepayid": "3209647863"
        }],
        "uuid": "9e4345db-6093-bb35-07d3-e335f1e28793"
    }
}

The expected object:

public record ResultList<T extends ResponseData>(

        @JsonProperty("signature")
        String signature,

        @JsonProperty("uuid")
        UUID uuid,

        @JsonProperty("method")
        Method method,

        @JsonProperty("data")
        @JsonTypeInfo(
                use = JsonTypeInfo.Id.NAME,
                include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
                property = "method")
        @JsonSubTypes({
                @JsonSubTypes.Type(value = AccountLedgerResponse.class, name = "AccountLedger")
        })
        List<T> data) {

    @Builder
    public ResultList {

    }
}

Solution

  • The List type can't be identified.

    Your TypeInfo for AccountLedger should identify a class that contains an array of AccountLedger.

    You have to have a class that contains the list, something like:

    AccountLedgerList {
        List<AccountLedger> data;
    }
    

    and then your method identifies the List object type:

    @JsonSubTypes({
        @JsonSubTypes.Type(value = AccountLedgerList.class, name = "AccountLedger")
    })