简体   繁体   中英

Retrofit POST contains null body

I'm setting up an api client with retrofit, and so far GETs are working fine, but I'm trying to create a new object with a POST, and instead of the object being sent as json, the request body just contains the string "null":

---> HTTP POST http://myapiurl
Content-Type: application/json; charset=UTF-8
Content-Length: 4
null
---> END HTTP (4-byte body)

Here is the method I'm trying to call:

@POST("/Monsters/")
Response new_monster(@Body Monster mon);

And here is how I'm calling it:

@Test
public void testNew_monster() throws Exception {
    //create a new monster object, and pass it to the function,
    //then query and verify it's in the results?
    Monster newmon = new Monster() {
        {
            name = "deleteme";
            description = "created by junit test testNew_monster";
            image_url = "http://i.imgur.com/";
            created_by = "";
            encoded_key = "";
        }
    };

    Response r = client.new_monster(newmon);
    assertEquals(201, r.getStatus());
    //sleep a couple seconds here?

    List<Monster> monsterList = client.monsters();
    assertTrue(monsterList.contains(newmon));
}

I am guessing something is going wrong when the object is serialized to json with GSON, but I'm unable to see anything helpful with the debugger during the serialization process...

I'm using GSON version 2.3.1

EDIT: Here's how I'm building the RestAdapter and the client:

static MonSpottingApi GetClient(boolean dbg)
{
    RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(API_URL)
            .build();

    if (dbg) restAdapter.setLogLevel(RestAdapter.LogLevel.FULL);

    MonSpottingApi client = restAdapter.create(MonSpottingApi.class);

    return client;
}

In the test case class:

MonSightingClient.MonSpottingApi client;

@Before
public void setUp() throws Exception {
    client = MonSightingClient.GetClient(true);
}

I suspected that the root cause was Gson, so I started making very simple tests and trying to get objects to correctly serialize using toJson(). I think I found a bug in Gson, where it fails if an object is initialized with double-brace syntax:

Using the example class found here

public class GitHubTest {

    //fails
    @Test
    public void testGson1() throws Exception {
        GitHubClient.Contributor contrib = new GitHubClient.Contributor() {
            {
                login = "someguy";
                contributions = 99;
            }
        };
        Gson gson = new Gson();
        String json = gson.toJson(contrib);
        System.out.println("contents of json string: " + json);
        assertNotEquals(json, "null");
    }

    //passes
    @Test
    public void testGson2() throws Exception {
        GitHubClient.Contributor contrib = new GitHubClient.Contributor();
        contrib.contributions = 99;
        contrib.login = "someguy";
        Gson gson = new Gson();
        String json = gson.toJson(contrib);
        System.out.println("contents of json string: " + json);
        assertNotEquals(json, "null");
    }
}

Is this a bug in Gson? Or is there some weird subtle Java reason that this happens? (Java is not my strongest language).

I had the same issue, and it looks like a Gson is not happy with the double-brace initialization of the object that is to be converted.

Replacing the double-brace initialization...

 AuthenticationRequest req = new AuthenticationRequest() {{
     setName("myName"); 
     setPassword("myPass");
 }}

with...

AuthenticationRequest req = new AuthenticationRequest();
req.setUserId("myName");
req.setPassword("myPass");

...did the trick.

You have to pass your interface class to create() method of Restadapter . Let's say your interface class is INewService (where you declared new_monster ), then GetClient should look like:

public static INewService GetClient(boolean dbg){

    RestAdapter restAdapter = new RestAdapter.Builder().
    .setEndpoint(API_URL).
    .setClient(new OkClient(new OkHttpClient()))
    .build();

    if (dbg) restAdapter.setLogLevel(RestAdapter.LogLevel.FULL);

    return restAdapter.create(INewService.class);
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM