0

I need to handle the return of a call, however it can return a Boolean or a object. When the phone number is found, it crash right into onFailure.

I'm looking for solutions but all found did not solve my problem.

My Interface:

public interface PessoaService {

    @FormUrlEncoded
    @POST("Pessoa/BuscaContatosAgenda/")
    Call<Boolean> buscaContatoAgenda(@Field("Identificador") String identificador,
                                     @Field("UnidadeId") String unidadeId,
                                     @Field("Telefones") ArrayList<String> telefone);
}

My RetrofitConfig

public class RetrofitConfig {
    private final Retrofit retrofit;

    public RetrofitConfig() {
        this.retrofit = new Retrofit.Builder()
                .baseUrl(DadosEmpresa.URL)
                //O método addConverterFactory recebe a classe que será responsável por lidar com a conversão
                .addConverterFactory(JacksonConverterFactory.create())
                //Utilizamos o método build para criar o objeto Retrofit
                .build();
    }

    public PessoaService getBuscaContatoAgenda() {
        return this.retrofit.create(PessoaService.class);
    }
}

My Activity Function:

 private void verificandoContatos() {
        cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null, null, null, ContactsContract.Contacts.DISPLAY_NAME);

        telefonesArrayList = new ArrayList<>();
        while (cursor.moveToNext()) {
            String telefone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            telefonesArrayList.add(telefone);
        }
        cursor.close();

        Call<Boolean> call = new RetrofitConfig().getBuscaContatoAgenda().buscaContatoAgenda(pessoa.getIdentificador(), DadosEmpresa.UnidadeID, telefonesArrayList);
        call.enqueue(new Callback<Boolean>() {
            @Override
            public void onResponse(Call<Boolean> call, Response<Boolean> response) {
                if (response.body() == true) {
                    Toast.makeText(AgendaContatoActivity.this, "Nenhum contato foi encontrado na sua agenda!", Toast.LENGTH_LONG).show();
                } else if (response.body() == false) {
                    Toast.makeText(AgendaContatoActivity.this, "Ocorreu um erro inesperado. Tente novamente mais tarde.", Toast.LENGTH_LONG).show();
                    Log.e(TAG, "onResponse: " + response.body().toString());
                } else {
                    Toast.makeText(AgendaContatoActivity.this, "Esses são seus contatos encontrados", Toast.LENGTH_LONG).show();
                    createRecyclerView();
                }
            }

            @Override
            public void onFailure(Call<Boolean> call, Throwable t) {
                Log.e(TAG, "onFailure: Erro ao enviar contatos: " + t.getMessage());
                Toast.makeText(getBaseContext(), "Ocorreu um erro inesperado. Tente novamente.", Toast.LENGTH_LONG).show();

            }
        });
    }

t.getMessage = com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.Boolean out of START_ARRAY token at [Source: okhttp3.ResponseBody$BomAwareReader@f41ca80; line: 1, column: 1]

EDIT/UPDATE/SOLUTION

I found a way to resolve my problem after help in comments. Is not the best way, but WORKS FOR THIS CASE:

 private void verificandoContatos() {
        cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null, null, null, ContactsContract.Contacts.DISPLAY_NAME);

        telefonesArrayList = new ArrayList<>();
        while (cursor.moveToNext()) {
            String telefone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            telefonesArrayList.add(telefone);
        }
        cursor.close();

        Call<ArrayList<GetContatoAgenda>> call = new RetrofitConfig().getBuscaContatoAgenda().buscaContatoAgenda(pessoa.getIdentificador(), DadosEmpresa.UnidadeID, telefonesArrayList);
        call.enqueue(new Callback<ArrayList<GetContatoAgenda>>() {
            @Override
            public void onResponse(Call<ArrayList<GetContatoAgenda>> call, Response<ArrayList<GetContatoAgenda>> response) {
                Toast.makeText(AgendaContatoActivity.this, "Esses são seus contatos encontrados em nossa aplicativo!", Toast.LENGTH_LONG).show();
                contatoArrayList = new ArrayList<GetContatoAgenda>();
                //Como a Callback do Retrofit já faz o mapeamento, então fazemos o contatoArrayList receber a response.body();
                contatoArrayList = response.body();
                createRecyclerView();
            }

            @Override
            public void onFailure(Call<ArrayList<GetContatoAgenda>> call, Throwable t) {
                Log.e(TAG, "onFailure: Erro ao enviar contatos: " + t.getMessage());
                Toast.makeText(getBaseContext(), "Ocorreu um erro inesperado. Tente novamente.", Toast.LENGTH_LONG).show();

            }
        });
    }

1 Answers1

0

The problem is in your model. You need to make sure that JSON response which you get is 100% fit the model you use for deserialization This line is a problem. Here suppose to be a model which you show in comments

Call<Boolean> call

When you got the JSON response you suppose to parse data from it. That is good topic how to do that Android parse JSONObject

Bo Z
  • 2,359
  • 1
  • 13
  • 31
  • This is my problem. I receive 2 JSON responses. Is there a way to make a generic retrofit callback? – Gabriel Júnior de Souza Jun 11 '19 at 13:24
  • @GabrielJúniordeSouza you have to make a model for each type of response and connect response to the model properly. It will not generate model for you. Glad to help you – Bo Z Jun 11 '19 at 13:57
  • @GabrielJúniordeSouza show your response what you got there? I guess it suppose to be an object NOT boolean. – Bo Z Jun 11 '19 at 14:24
  • The response return multiple results. If **TRUE**, the return is a message (because no contacts are found), if **FALSE**, the return is a error message and if catch on another excepetion, return a ArrayList of Contatos – Gabriel Júnior de Souza Jun 11 '19 at 14:37
  • @GabrielJúniordeSouza TRUE or FALSE is a VALUE of the result. Response suppose to be an OBJECT where value can be true or false. Where this response come from? Give the whole picture – Bo Z Jun 11 '19 at 14:40
  • The response in one of cases: Response{protocol=http/1.1, code=200, message=OK, url=http://beta-api.zappcard.com.br/Pessoa/BuscaContatosAgenda/} – Gabriel Júnior de Souza Jun 11 '19 at 14:40
  • @GabrielJúniordeSouza i need to see body of response here is an example https://jsonapi.org/examples/ which service this response comes from? – Bo Z Jun 11 '19 at 14:43
  • `{ "Identificador": "sample string 1", "UnidadeId": 2, "Telefones": [ "sample string 1", "sample string 2" ] }` – Gabriel Júnior de Souza Jun 11 '19 at 14:47
  • @GabrielJúniordeSouza here you go. So based on that you need a model like Sample.class -> String Identificator, int UnidadeId, Array samples. But here I don't see true or false. So to avoid error you need that kind of model. And only after you parsed the object you can build logic. Got it? – Bo Z Jun 11 '19 at 14:50
  • Ok, now the throwable.getMessage return this (My ContatoTelefone.class is the model): _JsonMappingException: Can not instantiate value of type [simple type, class com.eworld.zappcard.Classes.ContatoTelefone] from Boolean value (true)_ – Gabriel Júnior de Souza Jun 11 '19 at 16:11
  • @GabrielJúniordeSouza how you can get boolean value if in object you have only strings and int? – Bo Z Jun 11 '19 at 16:58
  • @ BorisRuzanov I have two responses: boolean and an object(Contato Telefone). I need to know how to make the generic CallBack for both. – Gabriel Júnior de Souza Jun 11 '19 at 17:08
  • @GabrielJúniordeSouza no you are wrong. It one response and ONE object which include one boolean field and second is Contato Telefone object. And ContatoTelefone has its own model. So you have to parse them separately. Your link does not work. So provide WORK link with response example – Bo Z Jun 11 '19 at 17:27
  • @GabrielJúniordeSouza give me the response I will give you models – Bo Z Jun 11 '19 at 17:44
  • I need a Retrofit generic call that can receive booleans and complex object – Gabriel Júnior de Souza Jun 12 '19 at 17:31
  • @GabrielJúniordeSouza you have to understand the difference between call and response. Call which you send could have parameters which you can generate. Response which you got suppose to have a model which you suppose to use. CALL and RESPONSE are separate its two different parts of the flow. My answer is your solution. You need to make a model thats it and it will work. – Bo Z Jun 12 '19 at 17:49
  • I know the difference between a CALL and a RESPONSE, i just tought you would understand what i needed. But since you didnt understood, here: my RESPONSE can come in two different ways: a) BOOLEAN b) Complex Object. Now i know that i have to make a model that have to support the response, but how can i achieve a model that can map either a boolean and a complex object at the same time? – Gabriel Júnior de Souza Jun 12 '19 at 18:02
  • @GabrielJúniordeSouza you CAN'T change the object just extract what you need from it. That boolean is just a VALUE of the object. So you just need to extract it. From server you will always as a response get an object. After that you just PARSE data from the object it can be boolean / string / int / lists / other objects. It can be very complexity response hierarchy with a lot of lists + objects + primitives. That doesn't matter you just need to parse what you need from it – Bo Z Jun 12 '19 at 18:05
  • @GabrielJúniordeSouza edded some info to my answer – Bo Z Jun 12 '19 at 18:19
  • @BorizRuzanov I found a way to solve my problem, is not the best way but thanks for your help. – Gabriel Júnior de Souza Jun 13 '19 at 13:16
  • @GabrielJúniordeSouza tell me? – Bo Z Jun 13 '19 at 13:17
  • @BorizRuzanov I create a model, like you did. Retrofit Callback already does the mapping with the Jackson, then we makes the contactArrayList receive a response.body (). I edited my question with the way I found (is not the best way, but works in this case) – Gabriel Júnior de Souza Jun 13 '19 at 13:27