Tom*_*iak 25 java rest json gson retrofit2
我创建了一个简单的REST端点:
http://<server_address>:3000/sizes
Run Code Online (Sandbox Code Playgroud)
此URL返回一个包含json数组的非常简单的响应,如下所示:
[
{ "id": 1, "name": "Small", "active": true },
{ "id": 2, "name": "Medium", "active": true },
{ "id": 3, "name": "Large", "active": true }
]
Run Code Online (Sandbox Code Playgroud)
现在,我正在尝试使用GSON的Retrofit 2来使用此响应.
我添加了一个模型:
@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;
}
Run Code Online (Sandbox Code Playgroud)
和服务:
public interface Service {
@GET("sizes")
Call<List<Size>> loadSizes();
}
Run Code Online (Sandbox Code Playgroud)
我已经实例化了一个改造:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://<server_address>:3000")
.addConverterFactory(GsonConverterFactory.create())
.build();
Run Code Online (Sandbox Code Playgroud)
我的服务:
Service service = retrofit.create(Service.class);
Run Code Online (Sandbox Code Playgroud)
现在,尝试调用数据:
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());
}
});
Run Code Online (Sandbox Code Playgroud)
什么最终有例外:
java.lang.IllegalStateException:预期BEGIN_OBJECT但在第1行第18列是STRING路径$ [0] .name
我认为错误是由此引起的,REST API返回一个数组或对象的响应.
无法修改REST服务,因此响应必须保持原样.
此外,使用纯GSON对上述json进行反序列化可以通过以下方式完成:
Type sizesType = new TypeToken<List<Size>>(){}.getType();
List<Size> size = new Gson().fromJson(json, sizesType);
Run Code Online (Sandbox Code Playgroud)
但我不知道如何让Retrofit 2使用它.
提前致谢.
xia*_*orm 19
最近我刚刚完成了一个与retrofit2相关的项目.根据我的来源,我将你所有的东西复制到我的项目中试一试,做一些小改动,它在我身边很有效.
在build.gradle中,添加以下内容:
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.okhttp3:okhttp:3.1.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
Run Code Online (Sandbox Code Playgroud)
型号:( 更新:关注tommus的情况,createdAt和updatedAt现在显示在他的json响应示例中,这两个值需要注释,因为模型中的名称不同于json respone)
public class Size {
private int id;
private String name;
private boolean active;
@SerializedName("created_at")
private String createdAt;
@SerializedName("updated_at")
private String updatedAt;
}
Run Code Online (Sandbox Code Playgroud)
服务:( 与您的完全相同)
public interface service {
@GET("sizes")
Call<List<Size>> loadSizes();
}
Run Code Online (Sandbox Code Playgroud)
RestClient :( 我在这里添加日志,以便您可以看到所有请求信息和响应信息,注意不要使用Localhost,而是使用URL中的服务器IP地址)
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.xiaoyaoworm.prolificlibrary.test.Service;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RestClient {
private static Service service;
public static Service getClient() {
if (service == null) {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
// Add logging into retrofit 2.0
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.interceptors().add(logging);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://YOURSERVERIPNOTLOCALHOST:3000/")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient.build()).build();
service = retrofit.create(Service.class);
}
return service;
}
}
Run Code Online (Sandbox Code Playgroud)
在您的活动中,添加此功能以运行您的代码:( 与您所做的完全相同.响应将是您的大小列表)
private void loadSize() {
Service serviceAPI = RestClient.getClient();
Call<List<Size>> loadSizeCall = serviceAPI.loadSizes();
loadSizeCall.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());
}
});
}
Run Code Online (Sandbox Code Playgroud)
这是我的github repo,我使用retrofit2.0进行简单的GET POST PUT DELETE工作.您可以将其用作参考.我的Github改造2.0回购
请使用以下内容:
build.gradle文件:
dependencies {
...
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.google.code.gson:gson:2.6.2'
}
Run Code Online (Sandbox Code Playgroud)
WebAPIService.java:
public interface WebAPIService {
@GET("/json.txt") // I use a simple json file to get the JSON Array as yours
Call<JsonArray> readJsonArray();
}
Run Code Online (Sandbox Code Playgroud)
Size.java:
public class Size {
@SerializedName("id")
private int id;
@SerializedName("name")
private String name;
@SerializedName("active")
private boolean active;
@SerializedName("created_At")
private String createdAt;
@SerializedName("updated_at")
private String updatedAt;
}
Run Code Online (Sandbox Code Playgroud)
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://...")
.addConverterFactory(GsonConverterFactory.create())
.build();
WebAPIService service = retrofit.create(WebAPIService.class);
Call<JsonArray> jsonCall = service.readJsonArray();
jsonCall.enqueue(new Callback<JsonArray>() {
@Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
String jsonString = response.body().toString();
Log.i("onResponse", jsonString);
Type listType = new TypeToken<List<Size>>() {}.getType();
List<Size> yourList = new Gson().fromJson(jsonString, listType);
Log.i("onResponse", yourList.toString());
}
@Override
public void onFailure(Call<JsonArray> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
Run Code Online (Sandbox Code Playgroud)
这是调试截图:
更新:您还可以使用以下选项:
@GET("/json.txt")
Call<List<Size>> readList();
Run Code Online (Sandbox Code Playgroud)
和
Call<List<Size>> listCall1 = service.readList();
listCall1.enqueue(new Callback<List<Size>>() {
@Override
public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {
for (Size size : response.body()){
Log.i("onResponse", size.toString());
}
}
@Override
public void onFailure(Call<List<Size>> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});
Run Code Online (Sandbox Code Playgroud)
有趣的是......我的代码非常好.至少在上面的问题中提出的那个.
我最终从我的Size
模型中删除了一行.
当我专注于代码本身(特别是Retrofit的配置)时,我完全忽略了导入.
事实证明 - Size
当我开始String
为模型的字段键入类时实现模型:
name
createdAt
updatedAt
IntelliJ IDEA的代码完成建议我
java.lang.String
com.sun.org.apache.xpath.internal.operations.String
什么完全搞砸了Gson
反序列化.
谈到奖励......
我决定将自己的答案标记为有效.为什么?
非常感谢上面的gentlmen提供的优质服务.
因为我只有一个赏金,所以我决定奖励xiaoyaoworm,因为他的代码更能满足我的需求(我没有在我的问题中写出来,但编写这样简单的服务的想法 - 就像我在我的问题中提出的那样 - 是隐藏从最终用户实现细节而不是JsonArray
在BNK响应中使用等.
xiaoyaoworm回答的唯一问题是,他建议Size
模型不需要任何注释,引用的JSON示例完全错误.
对于上述情况,确切的两个字段中的Size
模型需要注解 - created_at
和updated_at
.
我甚至测试了几个版本的converter-gson
库(我看到xiaoyaoworm使用了除了我之外) - 它没有改变任何东西.注释是必要的.
否则 - 再次,非常感谢!
归档时间: |
|
查看次数: |
21242 次 |
最近记录: |