预期 BEGIN_ARRAY 但在第 1 行第 2 列路径错误 BEGIN_OBJECT 使用改造应用程序和 spring 启动
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path error with using retrofit application and spring boot
我知道以前有人问过这个问题,但我似乎正在努力解决我的错误。我正在使用 Spring Boot 从 java 托管一个本地网站,现在我必须使用改造来实现一个 android 应用程序。我正在尝试完成一项简单的任务,即从我的网站将 json 对象加载到 android 上的回收视图,但出现以下错误:
2020-02-09 12:15:57.005 9204-9274/bootcamp.entelect.co.za.supermancomicstockapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: bootcamp.entelect.co.za.supermancomicstockapp, PID: 9204
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask.done(AsyncTask.java:353)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:117)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:211)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:89)
at bootcamp.entelect.co.za.supermancomicstockapp.Presenter.BrowsePresenter$BrowseTaskFirst.doInBackground(BrowsePresenter.java:50)
at bootcamp.entelect.co.za.supermancomicstockapp.Presenter.BrowsePresenter$BrowseTaskFirst.doInBackground(BrowsePresenter.java:36)
at android.os.AsyncTask.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
这是我的浏览器界面:
public interface IBrowse {
void loadFirst(List<BrowseDTO> browseDTOList);
void loadNext(List<BrowseDTO> browseDTOList);
}
我的浏览activity:
@Override
public void loadFirst(List<BrowseDTO> browseDTOList) {
recycleViewAdapter.addAll(browseDTOList);
if(currentPage <= TOTAL_PAGES) recycleViewAdapter.addLoadingFooter();
else isLastPage = true;
}
我的浏览器主持人:
public static class BrowseTaskFirst extends AsyncTask<Integer,Void,List<BrowseDTO>>{
IBrowse iBrowse;
public BrowseTaskFirst(IBrowse iBrowse) {
this.iBrowse = iBrowse;
}
@Override
protected List<BrowseDTO> doInBackground(Integer... integers) {
IBrowseService iBrowseService = APIClient.createService(IBrowseService.class, Token.getInstance());
Call<List<BrowseDTO>> browseIssuesPage;
browseIssuesPage = iBrowseService.getIssuesPaginated(integers[0]);
try{
return browseIssuesPage.execute().body();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(List<BrowseDTO> browseDTOS) {
super.onPostExecute(browseDTOS);
iBrowse.loadFirst(browseDTOS);
}
}
我的浏览器 DTO:
public class BrowseDTO {
IssueDTO issuesDTO;
private List<StockDTO> stockDTOlist;
public IssueDTO getIssuesDTO() {
return issuesDTO;
}
public List<StockDTO> getStockDTOlist() {
return stockDTOlist;
}
}
最后是我的浏览 service/controller
public interface IBrowseService {
@GET("/Browse/{pageNumber}")
Call<List<BrowseDTO>>getIssuesPaginated(
@Path("pageNumber") int pageNumber);
}
当 运行 应用程序时,我看到该应用程序正在与我的 spring 启动应用程序通信,因为它从网站获取数据,但在我尝试查看所有项目的列表时中断
更新
这是 JSON 响应:
content: [
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Average",
stockReferenceId: 49423,
availableQuantity: 0,
seriesNumber: 6,
price: 175.44,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Fine",
stockReferenceId: 24721,
availableQuantity: 1,
seriesNumber: 6,
price: 161.51,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Poor",
stockReferenceId: 74125,
availableQuantity: 0,
seriesNumber: 6,
price: 53.35,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Very Fine",
stockReferenceId: 19,
availableQuantity: 0,
seriesNumber: 6,
price: 43.06,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "Then I his alter'd hue perceiving, thus: "How may I speed, if thou yieldest to dread, Who still art wont to comfort me in doubt?"",
condition: "Average",
stockReferenceId: 49424,
availableQuantity: 0,
seriesNumber: 7,
price: 169.74,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "Then I his alter'd hue perceiving, thus: "How may I speed, if thou yieldest to dread, Who still art wont to comfort me in doubt?"",
condition: "Fine",
stockReferenceId: 24722,
availableQuantity: 0,
seriesNumber: 7,
price: 63.28,
publisher: "DC",
coverImage: "\Images.png"
},
您发布的模型不符合您在问题中添加的 json。在不添加任何类型的转换器的情况下使用改造时,java 模型应该与 json 本身匹配。命名也很重要。
要正确解析此对象:
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are
heard, there lamentations, moans, And blasphemies 'gainst the
good Power in heaven.",
condition: "Poor",
stockReferenceId: 74125,
availableQuantity: 0,
seriesNumber: 6,
price: 53.35,
publisher: "DC",
coverImage: "\Images.png"
}
你必须有一个具有相同结构的 java 对象:
class Item {
private String issueTitle;
private String description;
// and so on
}
下一步是解析这些项目的列表。由于您的 json 的根似乎是另一个对象,我们需要创建一个 java 模型,其结构与:
{
content: [
// ...
]
}
这可以通过以下模型实现:
class BrowseDTO {
private List<Item> content;
}
现在改造调用应该 return 这个 class:
public interface IBrowseService {
@GET("/Browse/{pageNumber}")
Call<BrowseDTO>getIssuesPaginated(
@Path("pageNumber") int pageNumber);
}
现在 return 是一个与 returned json 相匹配的对象。
你现在得到的错误是说你告诉改造你期望一个数组 - 那是 List<BrowseDTO>
- 但你得到的是一个对象 - 那是 json 中的根元素(content
).
在此示例中,我提到字段名称必须与 json 中的字段名称相匹配。这虽然没有错,但也未必是真的。由于您正在使用 Gson
,将名称更改为其他名称的最简单方法之一是使用注释 @SerializedName
,这将更改 json 中的名称并允许您使用任何字段你想要的名字,即:
class BrowseDTO {
@SerializedName("content")
private List<Item> items;
}
虽然这不一定适用于所有应用程序,但在 Android 中我们总是添加此注释,即使它与字段同名,因为发布版本经常被混淆并且字段名称不会肯定匹配 json 中的字段。
我知道以前有人问过这个问题,但我似乎正在努力解决我的错误。我正在使用 Spring Boot 从 java 托管一个本地网站,现在我必须使用改造来实现一个 android 应用程序。我正在尝试完成一项简单的任务,即从我的网站将 json 对象加载到 android 上的回收视图,但出现以下错误:
2020-02-09 12:15:57.005 9204-9274/bootcamp.entelect.co.za.supermancomicstockapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: bootcamp.entelect.co.za.supermancomicstockapp, PID: 9204
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask.done(AsyncTask.java:353)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:117)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:211)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:89)
at bootcamp.entelect.co.za.supermancomicstockapp.Presenter.BrowsePresenter$BrowseTaskFirst.doInBackground(BrowsePresenter.java:50)
at bootcamp.entelect.co.za.supermancomicstockapp.Presenter.BrowsePresenter$BrowseTaskFirst.doInBackground(BrowsePresenter.java:36)
at android.os.AsyncTask.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
这是我的浏览器界面:
public interface IBrowse {
void loadFirst(List<BrowseDTO> browseDTOList);
void loadNext(List<BrowseDTO> browseDTOList);
}
我的浏览activity:
@Override
public void loadFirst(List<BrowseDTO> browseDTOList) {
recycleViewAdapter.addAll(browseDTOList);
if(currentPage <= TOTAL_PAGES) recycleViewAdapter.addLoadingFooter();
else isLastPage = true;
}
我的浏览器主持人:
public static class BrowseTaskFirst extends AsyncTask<Integer,Void,List<BrowseDTO>>{
IBrowse iBrowse;
public BrowseTaskFirst(IBrowse iBrowse) {
this.iBrowse = iBrowse;
}
@Override
protected List<BrowseDTO> doInBackground(Integer... integers) {
IBrowseService iBrowseService = APIClient.createService(IBrowseService.class, Token.getInstance());
Call<List<BrowseDTO>> browseIssuesPage;
browseIssuesPage = iBrowseService.getIssuesPaginated(integers[0]);
try{
return browseIssuesPage.execute().body();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(List<BrowseDTO> browseDTOS) {
super.onPostExecute(browseDTOS);
iBrowse.loadFirst(browseDTOS);
}
}
我的浏览器 DTO:
public class BrowseDTO {
IssueDTO issuesDTO;
private List<StockDTO> stockDTOlist;
public IssueDTO getIssuesDTO() {
return issuesDTO;
}
public List<StockDTO> getStockDTOlist() {
return stockDTOlist;
}
}
最后是我的浏览 service/controller
public interface IBrowseService {
@GET("/Browse/{pageNumber}")
Call<List<BrowseDTO>>getIssuesPaginated(
@Path("pageNumber") int pageNumber);
}
当 运行 应用程序时,我看到该应用程序正在与我的 spring 启动应用程序通信,因为它从网站获取数据,但在我尝试查看所有项目的列表时中断
更新
这是 JSON 响应:
content: [
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Average",
stockReferenceId: 49423,
availableQuantity: 0,
seriesNumber: 6,
price: 175.44,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Fine",
stockReferenceId: 24721,
availableQuantity: 1,
seriesNumber: 6,
price: 161.51,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Poor",
stockReferenceId: 74125,
availableQuantity: 0,
seriesNumber: 6,
price: 53.35,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are heard, there lamentations, moans, And blasphemies 'gainst the good Power in heaven.",
condition: "Very Fine",
stockReferenceId: 19,
availableQuantity: 0,
seriesNumber: 6,
price: 43.06,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "Then I his alter'd hue perceiving, thus: "How may I speed, if thou yieldest to dread, Who still art wont to comfort me in doubt?"",
condition: "Average",
stockReferenceId: 49424,
availableQuantity: 0,
seriesNumber: 7,
price: 169.74,
publisher: "DC",
coverImage: "\Images.png"
},
{
issueTitle: "52",
description: "Then I his alter'd hue perceiving, thus: "How may I speed, if thou yieldest to dread, Who still art wont to comfort me in doubt?"",
condition: "Fine",
stockReferenceId: 24722,
availableQuantity: 0,
seriesNumber: 7,
price: 63.28,
publisher: "DC",
coverImage: "\Images.png"
},
您发布的模型不符合您在问题中添加的 json。在不添加任何类型的转换器的情况下使用改造时,java 模型应该与 json 本身匹配。命名也很重要。
要正确解析此对象:
{
issueTitle: "52",
description: "When they arrive before the ruinous sweep, There shrieks are
heard, there lamentations, moans, And blasphemies 'gainst the
good Power in heaven.",
condition: "Poor",
stockReferenceId: 74125,
availableQuantity: 0,
seriesNumber: 6,
price: 53.35,
publisher: "DC",
coverImage: "\Images.png"
}
你必须有一个具有相同结构的 java 对象:
class Item {
private String issueTitle;
private String description;
// and so on
}
下一步是解析这些项目的列表。由于您的 json 的根似乎是另一个对象,我们需要创建一个 java 模型,其结构与:
{
content: [
// ...
]
}
这可以通过以下模型实现:
class BrowseDTO {
private List<Item> content;
}
现在改造调用应该 return 这个 class:
public interface IBrowseService {
@GET("/Browse/{pageNumber}")
Call<BrowseDTO>getIssuesPaginated(
@Path("pageNumber") int pageNumber);
}
现在 return 是一个与 returned json 相匹配的对象。
你现在得到的错误是说你告诉改造你期望一个数组 - 那是 List<BrowseDTO>
- 但你得到的是一个对象 - 那是 json 中的根元素(content
).
在此示例中,我提到字段名称必须与 json 中的字段名称相匹配。这虽然没有错,但也未必是真的。由于您正在使用 Gson
,将名称更改为其他名称的最简单方法之一是使用注释 @SerializedName
,这将更改 json 中的名称并允许您使用任何字段你想要的名字,即:
class BrowseDTO {
@SerializedName("content")
private List<Item> items;
}
虽然这不一定适用于所有应用程序,但在 Android 中我们总是添加此注释,即使它与字段同名,因为发布版本经常被混淆并且字段名称不会肯定匹配 json 中的字段。