0

I'm trying to fetch JSON data from my website throw REST API with retrofit2. But when I run the app this error message show:

Can not find a (Map) Key deserializer for type [simple type, class com.example.app.ReferralApiModel]

I'm using retrofit library.

This is my code for the retrofit call:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(AppConfig.URL)
                .addConverterFactory(JacksonConverterFactory.create())
                .client(defaultHttpClient)
                .build();

        ReferralsPlaceHolderApi placeHolderApi = retrofit.create(ReferralsPlaceHolderApi.class);

        Call<List<Map<ReferralApiModel, String>>> call = placeHolderApi.getReferrals();

And this is my ReferralsPlaceHolderApi class:

public interface ReferralsPlaceHolderApi {

    @JsonDeserialize(keyAs = ReferralsCustomDeserializer.class)
    @GET(AppConfig.ENDPOINT_REFERRALS)
    Call<List<Map<ReferralApiModel, String>>> getReferrals();
}

Also this is my ReferralApiModel class:

public class ReferralApiModel {
    private String date;
    private String amount;
    private String currency;
    private String status;

    public ReferralApiModel() {}

    public ReferralApiModel(String date, String amount, String currency, String status) {
        this.date = date;
        this.amount = amount;
        this.currency = currency;
        this.status = status;
    }

    public String getDate() {
        return date;
    }

    public String getAmount() {
        return amount;
    }

    public String getCurrency() {
        return currency;
    }

    public String getStatus() {
        return status;
    }
}

This is the json data that I'm trying to get:

"[{\"id\":\"1\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"1\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"302\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 12:53:29\",\"status\":\"0\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"2\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"303\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:03:43\",\"status\":\"1\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"3\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"304\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:04:33\",\"status\":\"2\",\"payment\":\"0\",\"username\":\"aaa\"}]"

Can anyone help me with this?.

Also I've found that this problem may be a class mapping problem, from this answer : https://stackoverflow.com/a/16383752/8055951 If it's ?!, Can someone tell me how to map the ReferralsPlaceHolderApi class.

Thanks.

Hamid AK
  • 1
  • 2

1 Answers1

0

Jackson cannot deserialize custom classes as map keys. The key of your deserialized map is ReferralApiModel. I order to achieve it, you need to write your own KeyDeserializer and register it for your class with Jackson. You can see here or here how to do that.

Also the json string in the question makes it look as if you don't need to deserialize into List<Map<ReferralApiModel, String>>, but into List<ReferralApiModel> instead. Which would make writing custom key deseriaslizers redundant.

Edit: Ok, receiving json array, which has been json sting-ified is just strange. It would be best, if someone on your team is responsible for this API and can fix it. If not, you have workarounds:

  1. Parse twice with object mapper - first parse it to normal string, which would be json array, then parse this string into List<YourObject>
ObjectMapper mapper = new ObjectMapper();
String string = mapper.readValue(initialJson, String.class);
List<ReferralApiModel> list = mapper.readValue(string, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);
  1. Turn it manually into proper json array. That means remove first and last char - double quote, and remove all those escapes - \. Something like this:
String jsonString = "the string";
jsonString = jsonString.substring(1, jsonString.length() - 1).replace("\\", "");

ObjectMapper mapper = new ObjectMapper();
List<ReferralApiModel> list = mapper.readValue(jsonString, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);
Chaosfire
  • 4,818
  • 4
  • 8
  • 23
  • When I'm using **List** instead of **List>** this error message show **Expected BEGIN_ARRAY but was STRING at line 1 column 2 path $** – Hamid AK Feb 08 '22 at 12:22
  • @HamidAK The json string you posted **is** a `List`. Or are you saying the response you are trying to deserialize actually starts/ends with the double quotes - `"`? That would mean you are receiving literary a `json string`, **not** a `json array` and explains the error you described. – Chaosfire Feb 08 '22 at 15:09
  • Yeah actually it's starts/end with double quotes, any idea on how to handle this response?! – Hamid AK Feb 08 '22 at 16:20
  • @HamidAK See edit. – Chaosfire Feb 08 '22 at 17:10