javaandroidgsonretrofit2jdeveloper-11g

Why does the String coming in POST request body come with additional quotes and get not a JSON Object


I am calling a RestFul API written in Java that consumes plain text or JSON and returns a response in JSON. I am using gson library to generate and parse my fields. I am calling the api from an Android simulation where I user retrofit2 library and GsonConverterFactory. The generated String seems fine. I am not using a POJO, just a generic HashMap which I then convert to a String.

Generated gson from Android is {"password":"K16073","userid":"K16073"}

Code given below. At the API service, the string received is wrapped with additional double quotes.

Printed String including the quotes in the beginning and end "{\"password\":\"K16073\",\"userid\":\"K16073\"}"

Because of this I am getting java.lang.IllegalStateException: Not a JSON Object: "{\"password\":\"K16073\",\"userid\":\"K16073\"}"

I tried to remove the quotes and then I get com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Expected name at line 1 column 2 path $.

/* Android code */
Gson gson = new GsonBuilder()
                .setLenient()
                .create();

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(myRFReceivingApis.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

 Map<String, String> userData = new HashMap<>();
 userData.put("userid",edtTxtUserId.getText().toString());
 userData.put("password",editTxtPassword.getText().toString());
 Gson gson = new Gson();
 System.out.println(" generated gson " +gson.toJson(userData));
 call = ApiClient.getInstance().getMyApi().callLogin(gson.toJson(userData));
 call.enqueue(new Callback<Object>() {
            @Override
            public void onResponse(Call<Object> call, Response<Object> response) {
                textViewResp.setText(response.body().toString());
      :
/* End of Android code */

API Service code in Java

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON})
@Path("login")
public String RFLoginNew(String jsonString) {
    String result = jsonString.substring(1, jsonString.length() - 1);
    System.out.println(" Json String  "+result);
    // tried using JsonParser  -- line 1 below
    JsonObject o = JsonParser.parseString(result).getAsJsonObject();
    // tried using Gson gson.fromJson
    Gson gson = new Gson();
    JsonElement element = gson.fromJson (result, JsonElement.class); //Converts the json string to         JsonElement without POJO 
    JsonObject jsonObj = element.getAsJsonObject(); //Converting JsonElement to JsonObject
    // --line 2 below
    System.out.println("  RFLoginNew struser "+ jsonObj.get("userid").getAsString());

I am not getting the correct json format. I am not sure what is wrong with the way jsonString is generated.


Solution

  • Cause

    You are making double serialization.

    call = ApiClient.getInstance().getMyApi().callLogin(gson.toJson(userData));
    

    Here your map gets serialized to json string, and then this json gets serialized a second time when request is sent.

    Fix

    1. Serialize only once on frontend - whatever library you are using(i don't do android stuff) should have method where you supply the payload as an Оbject - the method argument should be the map, userData in your case.
    call = ApiClient.getInstance().getMyApi().callLogin(userData);
    

    Something like that.

    1. Or double deserialization on backend - deserialize to String, then deserialize the resulting string again to whatever you need.
    String jsonString = gson.fromJson(doubleJson, String.class);
    Map<String, String> result = gson.fromJson(jsonString, Map.class);
    System.out.println(result);