Retrofit对接Spring Boot报错:Expected BEGIN_ARRAY but was BEGIN_OBJECT
Expected BEGIN_ARRAY but was BEGIN_OBJECT错误 首先看你的错误日志,核心问题非常明确:java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT——Gson期望解析一个JSON数组,但实际收到的是一个JSON对象。结合你提供的接口返回数据,我来拆解问题和解决方案:
问题根源
你的Retrofit接口IBrowseService定义的返回类型是Call<List<BrowseDTO>>,也就是期望服务器直接返回一个BrowseDTO的数组。但实际服务器返回的是一个包裹了数组的对象,结构是这样的:
{ "content": [ // 你的漫画数据数组 ] }
Gson尝试把整个对象当成数组解析,自然就报错了。另外还有一个隐藏问题:你的BrowseDTO结构和返回的数组元素完全不匹配,这个也得一起修正。
分步解决方案
1. 创建分页响应DTO类
首先需要一个类来匹配服务器返回的外层对象,用来接收包含数组的content字段:
public class BrowsePageResponse { private List<BrowseDTO> content; // Getter和Setter public List<BrowseDTO> getContent() { return content; } public void setContent(List<BrowseDTO> content) { this.content = content; } }
2. 修改Retrofit接口的返回类型
把IBrowseService的返回类型从Call<List<BrowseDTO>>改成Call<BrowsePageResponse>:
public interface IBrowseService { @GET("/Browse/{pageNumber}") Call<BrowsePageResponse> getIssuesPaginated( @Path("pageNumber") int pageNumber); }
3. 调整Presenter里的解析逻辑
在BrowseTaskFirst的doInBackground方法中,先获取外层响应对象,再提取里面的content数组:
@Override protected List<BrowseDTO> doInBackground(Integer... integers) { IBrowseService iBrowseService = APIClient.createService(IBrowseService.class, Token.getInstance()); Call<BrowsePageResponse> browseIssuesPage = iBrowseService.getIssuesPaginated(integers[0]); try{ BrowsePageResponse response = browseIssuesPage.execute().body(); if (response != null) { return response.getContent(); // 提取真正需要的数组 } } catch (IOException e) { e.printStackTrace(); } return null; }
4. 修正BrowseDTO的结构
你的BrowseDTO现在是嵌套了IssueDTO和List<StockDTO>,但服务器返回的每个数组元素是平级的字段(比如issueTitle、condition等),所以必须把BrowseDTO改成和返回字段一一对应的结构:
public class BrowseDTO { private String issueTitle; private String description; private String condition; private int stockReferenceId; private int availableQuantity; private int seriesNumber; private double price; private String publisher; private String coverImage; // 生成所有字段的Getter和Setter方法 public String getIssueTitle() { return issueTitle; } public void setIssueTitle(String issueTitle) { this.issueTitle = issueTitle; } // 其他字段的Getter/Setter同理,这里省略 }
验证修改
做完这些修改后,重启App测试:
- Retrofit会先解析外层的
BrowsePageResponse对象 - 提取
content字段里的数组,转换成List<BrowseDTO> - 最终传递给
loadFirst方法加载到RecyclerView中
这样就能解决解析错误,同时保证数据能正确映射到DTO类里。
内容的提问来源于stack exchange,提问作者Mohammed Ismail

