31

I need to send next json via retrofit 2:

{
    "Inspection": {
        "UUID": "name",
        "ModifiedTime": "2016-03-09T01:13",
        "CreatedTime": "2016-03-09T01:13",
        "ReviewedWith": "name2",
        "Type": 1,
        "Project": {
            "Id": 41
        },
        "ActionTypes": [1]
    }   
}

With Header: Authorization: access_token_value

I tried this:

//header parameter
String accessToken = Requests.getAccessToken();

JsonObject obj = new JsonObject();
JsonObject inspection = new JsonObject();

inspection.addProperty("UUID","name");
inspection.addProperty("ModifiedTime","2016-03-09T01:13");
inspection.addProperty("CreatedTime","2016-03-09T01:13");
inspection.addProperty("ReviewedWith","name2");
inspection.addProperty("Type","1");

JsonObject project = new JsonObject();
project.addProperty("Id", 41);

inspection.add("Project", project);
obj.add("Inspection", inspection);

Retrofit restAdapter = new Retrofit.Builder()
        .baseUrl(Constants.ROOT_API_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addConverterFactory(ScalarsConverterFactory.create())
        .build();
IConstructSecureAPI service = restAdapter.create(IConstructSecureAPI.class);
Call<JsonElement> result = service.addInspection(accessToken, obj);
JsonElement element = result.execute().body();

But everytime i recieved exception: java.lang.IllegalArgumentException: Unable to create @Body converter for class com.google.gson.JsonObject (parameter #2)

How can I send it ? Or any another idea how I can do it. You can even offer me with parameter as simple String with json inside. It will suit for me

kkost
  • 3,640
  • 5
  • 41
  • 72

9 Answers9

32

Solution: declare body value in your interface with next:

@Body RequestBody body and wrap String JSON object:

RequestBody body = RequestBody.create(MediaType.parse("application/json"), obj.toString());

kkost
  • 3,640
  • 5
  • 41
  • 72
24

There is chance of you kept same @SerializedName("") for multiple vairable/fields/tags

Mohd Qasim
  • 896
  • 9
  • 20
21

You can specify a Converter when you create the Retrofit like this

Retrofit retrofit = new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl(baseurl)
        .client(okHttpClient)
        .build();
Emanuel
  • 863
  • 9
  • 29
4

If this is due to @SerializedName make sure it is not dulplicated.

For e.g. This error will be thrown in below case: (Note: bookingId is passed twice)

@SerializedName(value="bookingId", alternate={"id", "bookingId"})

But, this is the correct:

@SerializedName(value="bookingId", alternate={"id", "someOtherId", "whateverId"})
Prince
  • 20,353
  • 6
  • 39
  • 59
2

Body uses a single request object, declare your request object as following

class Inspection {
    String UUID;
    //..... add your fields 
    Project project;      
}

class Product
{
   int Id;
   //....... add your fields 
}

I assume your service IConstructSecureAPI endpoint is:

@GET(...)    // change based on your api GET/POST
Call<Response> addInspection(
    @Header("Authorization") String accesstoken, 
    @Body Inspection request
);

and you can declare your desire Response.

Check this answer, it uses HashMap instead of class.

Nikson Kanti Paul
  • 3,394
  • 1
  • 35
  • 51
  • Your answer is correct but I have forgot write ".addConverterFactory(GsonConverterFactory.create())" =) – Andrew G Feb 26 '20 at 11:20
1

I kept getting this error when I upgraded to Java 17, still working fine on Java 11.

Here's what worked for me

  • To go deeper into the Exception I put a debug point in the Utils.java found in retrofit stack trace.
  • Doing so led me to the narrower cause being: java.lang.reflect.InaccessibleObjectException: Unable to make field private final byte java.time.LocalTime.hour accessible: module java.base does not "opens java.time" to unnamed module @35e2d654
  • Googling down further from here led me to https://github.com/mockk/mockk/issues/681#issuecomment-959646598 which in a nutshell suggests to add --add-opens java.base/java.time=ALL-UNNAMED as a JVM argument.
  • Boom, It worked.
Harsh Gundecha
  • 1,139
  • 9
  • 16
1

I am using Moshi and Retrofit and my problem was I forgot to add @JsonSerializable annotation for the DTO class for @body. you should add this annotation like this:

@JsonSerializable
data class RegisterDTO(
    @field:Json(name = "device_id") val deviceId: String,
)
Sana Ebadi
  • 6,656
  • 2
  • 44
  • 44
1

In my case I simply forgot to apply the kotlinx.serialization plugin for Gradle, so no code for the serializers was generated. Fix it via:

plugins {
    kotlin("plugin.serialization")
}
sschuberth
  • 28,386
  • 6
  • 101
  • 146
0

You can use an Interceptor to send Authorization Header in each request

class AuthorizationInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        String authorizationToken = AuthenticationUtils.getToken();
        Request authorizedRequest = originalRequest.newBuilder()
            .header("Authorization", authorizationToken)
            .build();
        return chain.proceed(authorizedRequest);
    }
}
JJD
  • 50,076
  • 60
  • 203
  • 339
Darien Alvarez
  • 153
  • 2
  • 10