I am trying to translate some text by using Microsoft translator API . I am using Retrofit 2
. This is the code:
public RestClient() {
final OkHttpClient httpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
final Request originalRequest = chain.request();
Request newRequest;
newRequest = originalRequest.newBuilder()
.header("Content-Type", "application/json")
.header("Ocp-Apim-Subscription-Key", "KEY")
.header("X-ClientTraceId", java.util.UUID.randomUUID().toString())
.build();
return chain.proceed(newRequest);
}
})
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
// Build the retrofit config from our http client
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.cognitive.microsofttranslator.com/")
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Build api instance from retrofit config
api = retrofit.create(RestApi.class);
}
public interface RestApi {
@POST("translate?api-version=3.0&from=en&to=zh-Latn")
Call<TranslationResultDTO> getTranslation(@Body final RequestBody Text);
}
public void getTranslation(final String text, final RestCallback<TranslationResultDTO> translationResultCallback) {
final JsonObject jsonBody = new JsonObject();
jsonBody.addProperty("Text", text);
RequestBody textToTranslateBody = RequestBody.create(MediaType.parse("application/json"), jsonBody.toString());
Call<TranslationResultDTO> call = api.getTranslation(textToTranslateBody);
call.enqueue(new Callback<TranslationResultDTO>() {
@Override
public void onResponse(Call<TranslationResultDTO> call, retrofit2.Response<TranslationResultDTO> response) {
final int responseCode = response.code();
....
}
@Override
public void onFailure(Call<TranslationResultDTO> call, Throwable t) {
....
}
});
}
I get an error from the server. The error says that the body in not a valid JSON
.
Does someone know where is the problem?? Thanks in advance!
UPDATE
Here is the code for another solution I have tried as well. This solution is using a POJO class:
public class Data {
@SerializedName("Text")
private String text;
public Data(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
@POST("translate?api-version=3.0&from=en&to=zh-Latn")
Call<TranslationResultDTO> getTranslation(@Body final Data Text);
Data data = new Data("text value to translate");
Call<TranslationResultDTO> call = api.getTranslation(data);
Also the same error :/
The error says that the body in not a valid JSON.
It was an expected response from server. Let's say below is your JSON body that you want to send,
{
"key_1" : "value 1",
"key_2" : "value 2",
}
When you use JsonObject#toString()
, it'll become like this
{\"key_1\" : \"value 1\", \"key_2\" : \"value 2\"}
If you send above JSON data/body to the server, it'll be treated as normal String by the server.
Still you need to use toString()
here because MediaType#parse()
doesn't accept JsonObject
parameters.
What's the solution?
As Ishan Fernando mentioned in his comment you need to create a custom POJO class to prepare the JSON body for the request. Or use HashMap
to prepare the body.
Create POJO like below
import com.google.gson.annotations.SerializedName;
public class Data {
@SerializedName("Text")
private String text;
public Data(String text) {
this.text = text;
}
// getter and setter methods
}
And use it
Data data = new Data("text value to translate"); // construct object
Call<TranslationResultDTO> call = api.getTranslation(data); // change method parameter
And also adjust the method parameter in API interface
Call<TranslationResultDTO> getTranslation(@Body final Data text); // change method parameter
Edit 1
I went through the documentation attached to your question. I made a little mistake. JSON body should contain JSONArray, not JSONObject. Like below
[
{
"Text" : "text to translate"
}
]
Change method parameter to List<Data>
in the API interface
Call<TranslationResultDTO> getTranslation(@Body final List<Data> text); // change method parameter
Use it like below
Data data = new Data("text value to translate"); // construct object
List<Data> objList = new ArrayList<>();
objList.add(data);
Call<TranslationResultDTO> call = api.getTranslation(objList); // change method parameter
Edit 2
And also API will respond with JSONArray. Sample response
[
{
"detectedLanguage": {
"language": "en",
"score": 1.0
},
"translations": [
{
"text": "Hallo Welt!",
"to": "de"
},
{
"text": "Salve, mondo!",
"to": "it"
}
]
}
]
Create below POJO classes to parse JSON response properly
Translation.java
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Translation {
@SerializedName("text")
@Expose
private String text;
@SerializedName("to")
@Expose
private String to;
// constructors, getter and setter methods
}
DetectedLanguage.java
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class DetectedLanguage {
@SerializedName("language")
@Expose
private String language;
@SerializedName("score")
@Expose
private float score;
// constructors, getter and setter methods
}
And finally, adjust TranslationResultDTO.java class like below.
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class TranslationResultDTO {
@SerializedName("detectedLanguage")
@Expose
private DetectedLanguage detectedLanguage;
@SerializedName("translations")
@Expose
private List<Translation> translations = null;
// constructors, getter and setter methods
}
Interface class
Call<List<TranslationResultDTO>> call = api.getTranslation(objList); // change method parameter
If you see the method right, u need to pass JsonObject:
Call<TranslationResultDTO> getTranslation(@Body final JsonObject Text)
But instead you are passing "textToTranslateBody" which is of type RequestBody not JsonObject. You have to pass "jsonBody" which is of type JsonObject.
This is what works me for the current version of retrofit
2.6.2 ,
First of all, we need to add a Scalars Converter to the list of our Gradle dependencies, which would take care of converting java.lang.String objects to text/plain request bodies,
implementation'com.squareup.retrofit2:converter-scalars:2.6.2'
Then, we need to pass a converter factory to our Retrofit builder. It will later tell Retrofit how to convert the @Body parameter passed to the service.
private val retrofitBuilder: Retrofit.Builder by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
}
Note: In my retrofit builder i have two converters
Gson
andScalars
you can use both of them put to send Json body we need to focus so if you don't needGson
remove it
Then Retrofit service with a String body parameter.
@Headers("Content-Type: application/json")
@POST("users")
fun saveUser(@Body user: String): Response<MyResponse>
Then create the json body
val user = JsonObject()
user.addProperty("id", 001)
user.addProperty("name", "Name")
Call your service
RetrofitService.myApi.saveUser(user.toString())
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.