I've created a simple REST endpoint:
http://<server_address>:3000/sizes
This URL returns a very simple response containing a json array as follows:
[
{ "id": 1, "name": "Small", "active": true },
{ "id": 2, "name": "Medium", "active": true },
{ "id": 3, "name": "Large", "active": true }
]
Now, I'm trying to consume this response using Retrofit 2 with GSON.
I've added a model:
@lombok.AllArgsConstructor
@lombok.EqualsAndHashCode
@lombok.ToString
public class Size {
private int id;
private String name;
private boolean active;
@SerializedName("created_at")
private String createdAt;
@SerializedName("updated_at")
private String updatedAt;
}
And service:
public interface Service {
@GET("sizes")
Call<List<Size>> loadSizes();
}
I've instantiated a Retrofit:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://<server_address>:3000")
.addConverterFactory(GsonConverterFactory.create())
.build();
And my service:
Service service = retrofit.create(Service.class);
Now, trying to call the data:
service.loadSizes().enqueue(new Callback<List<Size>>() {
@Override
public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {
for(Size size: response.body()) {
System.out.println(size.toString());
}
}
@Override
public void onFailure(Call<List<Size>> call, Throwable t) {
System.out.println(t.getMessage());
}
});
What ends up with an exception:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 18 path $[0].name
I suppose the error is caused by that, the REST API returns a response which is an array nor object.
- Am I correct?
- What is the easiest way to make this code to work?
REST service cannot be modified, so the response must stay as is.
Also, deserialization of the above json using pure GSON might be done by:
Type sizesType = new TypeToken<List<Size>>(){}.getType();
List<Size> size = new Gson().fromJson(json, sizesType);
But I have no idea how to make Retrofit 2 to use this.
Thanks in advance.
Recently I just finish one project related to retrofit2. Based on my source, I copy all your stuff into my project to give a try, making some minor change, it works well on my side.
In your build.gradle, add those:
Model: (UPDATE: Follow tommus's case, createdAt and updatedAt is now shown in his json response sample, these two values needs annotation due to the name in the model is different from json respone)
Service: (Exactly same as what you have)
RestClient: (I add log here, so that you can see all the request info and response info, be careful not using Localhost but your server ip address in the URL )
On your activity, add this function to run your code: (exactly same as what you have done. The response will be your list of size)
Running this you will see the info you want to print out:
Here is my github repo which I use retrofit2.0 to make simple GET POST PUT DELETE work. You can use this as reference. My Github retrofit2.0 repo
The funny fact is... My code is perfectly fine. At least the one presented in the question above.
I've ended up removing one line from my
Size
model.As I focused on the code itself (especially Retrofit's configuration) I've totally ignored imports.
It turned out - while implementing
Size
model when I've started typingString
class for model's fields:name
createdAt
updatedAt
IntelliJ IDEA's code completion suggested me
java.lang.String
com.sun.org.apache.xpath.internal.operations.String
what totally messed up
Gson
's deserialization.When it comes to rewards...
I've decided to mark as valid my own answer. Why?
Many thanks goes to gentlmen above for their great services.
As I have only one bounty I've decided reward xiaoyaoworm as his code better match my needs (I haven't written it in my question but the idea of writing such simple service - as I've presented in my question - is to hide from the end-user implementation details and not use
JsonArray
and such like in BNK response).Update 1:
The only problem with xiaoyaoworm's answer is that, he suggested the
Size
model do not need any annotations what is totally wrong for the quoted JSON example.For above case, exact two fields of the
Size
model needs annotations -created_at
andupdated_at
.I've even tested few versions of the
converter-gson
library (I saw xiaoyaoworm have used other than me) - it hasn't changed anything. Annotations were necessary.Otherwise - again, many thanks!
Please use the following:
build.gradle file:
WebAPIService.java:
Size.java:
MainActivity.java:
Here is the debug screenshot:
UPDATE: You can also use the following option:
and