Search code examples
javajaxbjacksonjaxb2jersey-client

Unable to parse object being returned as either START_OBJECT or START_ARRAY in the response


In one of the APIs of Expedia Affiliate Network, below part of the response is being returned as array for a few items whereas object for others,

"Surcharges": {
       "Surcharge": {
                "_type": "TaxAndServiceFee",
                "_amount": "11.94"
        },
        "_size": "1"
}

"Surcharges": {
       "Surcharge": [
            {
                    "_type": "TaxAndServiceFee",
                    "_amount": "11.94"
            },
            {
                    "_type": "Somethingelse",
                    "_amount": "11.94"
            }
        ],
        "_size": "1"
}

The corresponding JAXB model is

@JsonPropertyOrder({
    "@size",
    "Surcharge"
})
@JsonIgnoreProperties(ignoreUnknown = true)
public class Surcharges {

    @JsonProperty("@size")
    private String Size;
    @JsonProperty("Surcharge")
    private Surcharge[] Surcharge;
    //was not part of the original model, added hoping this might solve :(
    @JsonProperty("Surcharge")
    private Surcharge Surcharge1;

    .....
}

The parse fails with

com.sun.jersey.api.client.ClientHandlerException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of in.xxx.xxxxx.port.adapter.expedia.hotels.list.response.Surcharge out of START_ARRAY token

and changing the Surcharge to array will result in

com.sun.jersey.api.client.ClientHandlerException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of in.xxx.xxxxxx.port.adapter.expedia.hotels.list.response.Surcharge out of START_OBJECT token

What is the best way to handle this response

I could find the solution in the Jackson Feature configuration

ACCEPT_SINGLE_VALUE_AS_ARRAY, how to set that with the ClientConfig of Jersey?


Solution

  • Resolved configuring JacksonJaxbProvider with the Client

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
    
    JacksonJaxbJsonProvider jacksonProvider = new JacksonJaxbJsonProvider();
    jacksonProvider.setMapper(mapper);
    config.getSingletons().add(jacksonProvider);