如何在Android应用中调用返回ResponseEntity的SpringBoot API?
我需要调用一个基于SpringBoot 3编写的服务器API,API定义如下:
public ResponseEntity<List<PostDTO>> getPosts();
在Android Studio的Java应用中使用Retrofit2(依赖:implementation 'com.squareup.retrofit2:retrofit:2.11.0')实现调用时,我在PostService.java里尝试了两种写法:
第一种:
@GET("v1/profiles/gigio/posts") Response<List<Post>> getPosts();
第二种:
@GET("v1/profiles/gigio/posts") Call<List<Post>> getPosts();
调用代码如下:
// retrieve posts for home page from server postService = RetrofitClient.getClient().create(PostService.class); Call<List<Post>> call = postService.getPosts();
结果触发了JNI错误,错误信息末尾内容:
2024-08-05 20:01:23.621 29123-29123 example.app com.example.app A runtime.cc:699] JNI DETECTED ERROR IN APPLICATION: the return type of CallObjectMethodA does not match retrofit2.Response com.example.app.service.PostService.getPosts() runtime.cc:699] in call to CallObjectMethodA runtime.cc:699] from void com.example.app.fragment.community.CommunityFragment.onViewCreated(android.view.View, android.os.Bundle) 2024-08-05 20:01:35.276 29123-29123 libc com.example.app A Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 29123 (example.app), pid 29123 (example.app)
Post和PostDTO字段完全一致,我认为问题出在ResponseEntity上,想找到客户端侧的解决方案,无需修改服务器,请问有没有办法在客户端处理服务器返回的ResponseEntity?
核心问题
JNI错误的直接原因是Retrofit接口定义的返回类型与调用时的接收类型不匹配——你用Call<List<Post>>接收返回值,但接口写的是Response<List<Post>>(或反过来),导致反射调用时类型兼容失败。另外,SpringBoot的ResponseEntity本质是封装了响应体、状态码、响应头的结构,Retrofit可以直接在客户端映射处理,无需修改服务器。
具体实现步骤
创建客户端版ResponseEntity实体类
对应SpringBoot返回的ResponseEntity结构,在客户端定义实体类来映射JSON响应:public class ResponseEntity<T> { private T body; private int statusCode; private Map<String, List<String>> headers; // 生成getter、setter方法(可使用Lombok简化) public T getBody() { return body; } public void setBody(T body) { this.body = body; } public int getStatusCode() { return statusCode; } public void setStatusCode(int statusCode) { this.statusCode = statusCode; } public Map<String, List<String>> getHeaders() { return headers; } public void setHeaders(Map<String, List<String>> headers) { this.headers = headers; } }注意:如果服务器返回的
statusCode是字符串枚举格式(如"statusCode": "OK"),需调整字段类型为String或自定义枚举类匹配。统一Retrofit接口与调用的类型
选择以下两种统一的实现方式之一:方式一:使用Call封装(同步/异步通用)
接口定义:
@GET("v1/profiles/gigio/posts") Call<ResponseEntity<List<Post>>> getPosts();调用代码(异步示例):
postService = RetrofitClient.getClient().create(PostService.class); Call<ResponseEntity<List<Post>>> call = postService.getPosts(); call.enqueue(new Callback<ResponseEntity<List<Post>>>() { @Override public void onResponse(Call<ResponseEntity<List<Post>>> call, retrofit2.Response<ResponseEntity<List<Post>>> response) { if (response.isSuccessful()) { ResponseEntity<List<Post>> serverResp = response.body(); List<Post> posts = serverResp.getBody(); // 业务数据处理 } } @Override public void onFailure(Call<ResponseEntity<List<Post>>> call, Throwable t) { // 错误处理 } });方式二:使用Response封装(适合同步调用)
接口定义:
@GET("v1/profiles/gigio/posts") Response<ResponseEntity<List<Post>>> getPosts();同步调用代码(需捕获IO异常):
try { Response<ResponseEntity<List<Post>>> response = postService.getPosts().execute(); if (response.isSuccessful()) { List<Post> posts = response.body().getBody(); // 业务数据处理 } } catch (IOException e) { e.printStackTrace(); }配置JSON转换器
必须添加Retrofit的JSON转换器依赖,否则无法解析响应:// Gson转换器示例 implementation 'com.squareup.retrofit2:converter-gson:2.11.0'并在Retrofit实例创建时添加转换器:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("你的服务器基础URL") .addConverterFactory(GsonConverterFactory.create()) .build();
关键注意事项
- 接口定义的返回类型必须与调用时的接收类型完全一致,不能混用
Call<X>和Response<X>,这是解决JNI错误的核心。 - 客户端
ResponseEntity的字段名必须与服务器返回的JSON结构严格匹配,否则会出现解析失败或字段为空的情况。
内容的提问来源于stack exchange,提问作者Francesco

