Hello. I am trying to connect to the Yandex translator API.
When converting response using gson in the string:

 mapGetResponse = gson.fromJson(response.body().toString(), Map.class); 

Gives an error message:

com.google.gson.JsonSyntaxException:
com.google.gson.stream.MalformedJsonException:
Unterminated array at line 1 column 35 path $. [1]

And this happens only if the translation is returned from more than one word. If you translate only one word, then everything is fine.

MainActivity

 public class MainActivity extends AppCompatActivity { public final String URL = "https://translate.yandex.net"; public final String KEY = "trnsl.1.1.20160324T093729Z.b14b7c54accb1f8e.7d811d65e5f9b19b5541568a35af1e6c8019b10e"; private TextView tvTranslate; private EditText etInputText; private Gson gson; private Retrofit retrofit; private YandexTranslateService service; private Map<String, String> mapJson, mapGetResponse; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvTranslate = (TextView) findViewById(R.id.tvTranslate); etInputText = (EditText) findViewById(R.id.etInputText); gson = new GsonBuilder().create(); retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create(gson)) .baseUrl(URL) .build(); service = retrofit.create(YandexTranslateService.class); } public void onClickTranslate(View view) { mapJson = new HashMap<>(); mapJson.put("key", KEY); mapJson.put("text", etInputText.getText().toString()); mapJson.put("lang", "en-ru"); ResponseTask responseTask = new ResponseTask(); responseTask.execute(); try { Response<Object> response = responseTask.get(); System.out.println(response.body()); mapGetResponse = gson.fromJson(response.body().toString(), Map.class); System.out.println(mapGetResponse); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } for (Map.Entry e: mapGetResponse.entrySet()){ if (e.getKey().equals("text")) { tvTranslate.setText(e.getValue().toString()); } } } public void onClickClear(View view){ tvTranslate.setText(""); etInputText.setText(""); } class ResponseTask extends AsyncTask<Void, Void, Response<Object>>{ Response<Object> response; @Override protected Response<Object> doInBackground(Void... params) { Call<Object> call = service.translate(mapJson); try { response = call.execute(); } catch (IOException e) { e.printStackTrace(); } return response; } } } 

YandexTranslateService

 public interface YandexTranslateService { @FormUrlEncoded @POST("/api/v1.5/tr.json/translate") Call<Object> translate(@FieldMap Map<String, String> map); } 

Error code

 03-25 06:33:05.026 19719-19719/com.gotb.testretrofit E/AndroidRuntime: FATAL EXCEPTION: main java.lang.IllegalStateException: Could not execute method for android:onClick at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293) at android.view.View.performClick(View.java:4204) at android.view.View$PerformClick.run(View.java:17355) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) at android.view.View.performClick(View.java:4204) at android.view.View$PerformClick.run(View.java:17355) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) Caused by: com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated array at line 1 column 35 path $.[1] at com.google.gson.Gson.fromJson(Gson.java:894) at com.google.gson.Gson.fromJson(Gson.java:844) at com.google.gson.Gson.fromJson(Gson.java:793) at com.google.gson.Gson.fromJson(Gson.java:765) at com.gotb.testretrofit.MainActivity.onClickTranslate(MainActivity.java:65) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) at android.view.View.performClick(View.java:4204) at android.view.View$PerformClick.run(View.java:17355) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) Caused by: com.google.gson.stream.MalformedJsonException: Unterminated array at line 1 column 35 path $.[1] at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1567) at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:480) at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:418) at com.google.gson.internal.bind.ObjectTypeAdapter.read(ObjectTypeAdapter.java:60) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:187) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) at com.google.gson.Gson.fromJson(Gson.java:879) at com.google.gson.Gson.fromJson(Gson.java:844) at com.google.gson.Gson.fromJson(Gson.java:793) at com.google.gson.Gson.fromJson(Gson.java:765) at com.gotb.testretrofit.MainActivity.onClickTranslate(MainActivity.java:65) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) at android.view.View.performClick(View.java:4204) at android.view.View$PerformClick.run(View.java:17355) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) 
  • Add json answer - Chaynik

2 answers 2

A little work on the bugs.

1) retrofit requests are executed in a separate thread. You do not need AsyncTask.

 service.translate(mapJson).enqueue(new Callback<TranslateData>() { @Override public void onResponse(Call<TranslateData> call, Response<TranslateData> response) { TranslateData data = response.body(); } @Override public void onFailure(Call<TranslateData> call, Throwable t) { } }); 

2) Create a class for serialization (an example is given based on your answer)

 public class TranslateData { private int code; private String lang; private ArrayList<String> text; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getLang() { return lang; } public void setLang(String lang) { this.lang = lang; } public ArrayList<String> getText() { return text; } public void setText(ArrayList<String> text) { this.text = text; } } 

3) Update the YandexTranslateService interface.

 Call<TranslateData> translate(@FieldMap Map<String, String> map); 

4) Update the code as in step 1.

After you receive the response from the server, you will already have a serialized response ready and you will not need to serialize the mapGetResponse = gson.fromJson(response.body().toString(), Map.class);

You have already added a serializer to the retrofit .addConverterFactory(GsonConverterFactory.create(gson)) .

  • I do not quite understand what it means to "Drop the answer Json in two versions." service.translate (mapJson) .enqueue (new Callback <Object> () {Override public void onResponse (Response <Object> response, Retrofit retrofit) {mapGetResponse = gson.fromJson (response.body (). toString (), Map. class);} Override public void onFailure (Throwable t) {}}); responce is a Json answer, right? For the remark about a separate stream retrofit, a separate thank you. - Tron
  • Json is what you get before you serialize it into an object. - Chaynik
  • just an example of a response from the server, what you have in response.body () - Chaynik
  • {code = 200.0, lang = en-ru, text = [i]} - Tron
  • I understand this {"code": 200.0, "lang": "en-ru", "text": [me]} - Chaynik
 gson.fromJson(response.body().toString(), Map.class); 

I had an error 27.

In response.body().toString() in the field were string fields of several words. It was necessary to add additional brackets when forming json on the server.

When in response.body().toString() came {message:"no data"} - this caused a conversion error.

{message:"'no data'"} - did not cause an error.