GSON抛出“预期的BEGIN_OBJECT,但是begin_array”;?

我试图解析这样的JSON字符串

[
{
"updated_at":"2012-03-02 21:06:01",
"fetched_at":"2012-03-02 21:28:37.728840",
"description":null,
"language":null,
"title":"JOHN",
"url":"http://rus.JOHN.JOHN/rss.php",
"icon_url":null,
"logo_url":null,
"id":"4f4791da203d0c2d76000035",
"modified":"2012-03-02 23:28:58.840076"
},
{
"updated_at":"2012-03-02 14:07:44",
"fetched_at":"2012-03-02 21:28:37.033108",
"description":null,
"language":null,
"title":"PETER",
"url":"http://PETER.PETER.lv/rss.php",
"icon_url":null,
"logo_url":null,
"id":"4f476f61203d0c2d89000253",
"modified":"2012-03-02 23:28:57.928001"
}
]

变成一个对象列表。

List<ChannelSearchEnum> lcs = (List<ChannelSearchEnum>) new Gson().fromJson( jstring , ChannelSearchEnum.class);

这是我使用的一个对象类。

import com.google.gson.annotations.SerializedName;


public class ChannelSearchEnum {






@SerializedName("updated_at")
private String updated_at;


@SerializedName("fetched_at")
private String fetched_at;


@SerializedName("description")
private String description;


@SerializedName("language")
private String language;


@SerializedName("title")
private String title;


@SerializedName("url")
private String url;


@SerializedName("icon_url")
private String icon_url;


@SerializedName("logo_url")
private String logo_url;


@SerializedName("id")
private String id;


@SerializedName("modified")
private String modified;


public final String get_Updated_at() {
return this.updated_at;
}


public final String get_Fetched_at() {
return this.fetched_at;
}


public final String get_Description() {
return this.description;
}


public final String get_Language() {
return this.language;
}


public final String get_Title() {
return this.title;
}


public final String get_Url() {
return this.url;
}


public final String get_Icon_url() {
return this.icon_url;
}


public final String get_Logo_url() {
return this.logo_url;
}


public final String get_Id() {
return this.id;
}


public final String get_Modified() {
return this.modified;
}


}

但这让我

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2

有什么好办法吗?

521786 次浏览

问题是你告诉Gson你有一个你的类型的对象。你不。你有一个自己类型的对象数组。你不能只是尝试这样的结果,并期望它神奇地工作;)

Gson的用户指南解释了如何处理这个问题:

https://github.com/google/gson/blob/master/UserGuide.md

这是可行的:

ChannelSearchEnum[] enums = gson.fromJson(yourJson, ChannelSearchEnum[].class);

但这样更好:

Type collectionType = new TypeToken<Collection<ChannelSearchEnum>>(){}.getType();
Collection<ChannelSearchEnum> enums = gson.fromJson(yourJson, collectionType);

根据用户指南,你不能。

集合的局限性

可以序列化任意对象的集合,但不能从它反序列化。因为用户无法指示结果对象的类型

问题是你请求的是一个ChannelSearchEnum类型的对象,但实际上你得到的是一个List<ChannelSearchEnum>类型的对象。

你可以通过以下方法实现:

Type collectionType = new TypeToken<List<ChannelSearchEnum>>(){}.getType();
List<ChannelSearchEnum> lcs = (List<ChannelSearchEnum>) new Gson()
.fromJson( jstring , collectionType);

另一种选择是

让你的回答看起来像

myCustom_JSONResponse

{"master":[
{
"updated_at":"2012-03-02 21:06:01",
"fetched_at":"2012-03-02 21:28:37.728840",
"description":null,
"language":null,
"title":"JOHN",
"url":"http://rus.JOHN.JOHN/rss.php",
"icon_url":null,
"logo_url":null,
"id":"4f4791da203d0c2d76000035",
"modified":"2012-03-02 23:28:58.840076"
},
{
"updated_at":"2012-03-02 14:07:44",
"fetched_at":"2012-03-02 21:28:37.033108",
"description":null,
"language":null,
"title":"PETER",
"url":"http://PETER.PETER.lv/rss.php",
"icon_url":null,
"logo_url":null,
"id":"4f476f61203d0c2d89000253",
"modified":"2012-03-02 23:28:57.928001"
}
]
}

而不是

server_JSONResponse

[
{
"updated_at":"2012-03-02 21:06:01",
"fetched_at":"2012-03-02 21:28:37.728840",
"description":null,
"language":null,
"title":"JOHN",
"url":"http://rus.JOHN.JOHN/rss.php",
"icon_url":null,
"logo_url":null,
"id":"4f4791da203d0c2d76000035",
"modified":"2012-03-02 23:28:58.840076"
},
{
"updated_at":"2012-03-02 14:07:44",
"fetched_at":"2012-03-02 21:28:37.033108",
"description":null,
"language":null,
"title":"PETER",
"url":"http://PETER.PETER.lv/rss.php",
"icon_url":null,
"logo_url":null,
"id":"4f476f61203d0c2d89000253",
"modified":"2012-03-02 23:28:57.928001"
}
]

代码

  String server_JSONResponse =.... // the string in which you are getting your JSON Response after hitting URL
String myCustom_JSONResponse="";// in which we will keep our response after adding object element to it
MyClass apiResponse = new MyClass();


myCustom_JSONResponse="{\"master\":"+server_JSONResponse+"}";






apiResponse = gson.fromJson(myCustom_JSONResponse, MyClass .class);

在此之后,它将是任何其他GSON Parsing

在我的例子中是JSON字符串:

[{"category":"College Affordability",
"uid":"150151",
"body":"Ended more than $60 billion in wasteful subsidies for big banks and used the savings to put the cost of college within reach for more families.",
"url":"http:\/\/www.whitehouse.gov\/economy\/middle-class\/helping middle-class-families-pay-for-college",
"url_title":"ending subsidies for student loan lenders",
"type":"Progress",
"path":"node\/150385"}]

然后在recycleview中打印“category”和“url_title”

Datum.class

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;


public class Datum {
@SerializedName("category")
@Expose
private String category;
@SerializedName("uid")
@Expose
private String uid;
@SerializedName("url_title")
@Expose
private String urlTitle;


/**
* @return The category
*/
public String getCategory() {
return category;
}


/**
* @param category The category
*/
public void setCategory(String category) {
this.category = category;
}


/**
* @return The uid
*/
public String getUid() {
return uid;
}


/**
* @param uid The uid
*/
public void setUid(String uid) {
this.uid = uid;
}


/**
* @return The urlTitle
*/
public String getUrlTitle() {
return urlTitle;
}


/**
* @param urlTitle The url_title
*/
public void setUrlTitle(String urlTitle) {
this.urlTitle = urlTitle;
}


}

RequestInterface

import java.util.List;


import retrofit2.Call;
import retrofit2.http.GET;


/**
* Created by Shweta.Chauhan on 13/07/16.
*/


public interface RequestInterface {


@GET("facts/json/progress/all")
Call<List<Datum>> getJSON();
}

DataAdapter

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


import java.util.ArrayList;
import java.util.List;


/**
* Created by Shweta.Chauhan on 13/07/16.
*/


public class DataAdapter extends RecyclerView.Adapter<DataAdapter.MyViewHolder>{


private Context context;
private List<Datum> dataList;


public DataAdapter(Context context, List<Datum> dataList) {
this.context = context;
this.dataList = dataList;
}


@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.data,parent,false);
return new MyViewHolder(view);
}


@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.categoryTV.setText(dataList.get(position).getCategory());
holder.urltitleTV.setText(dataList.get(position).getUrlTitle());


}


@Override
public int getItemCount() {
return dataList.size();
}


public class MyViewHolder extends RecyclerView.ViewHolder{


public TextView categoryTV, urltitleTV;


public MyViewHolder(View itemView) {
super(itemView);
categoryTV = (TextView) itemView.findViewById(R.id.txt_category);
urltitleTV = (TextView)     itemView.findViewById(R.id.txt_urltitle);
}
}
}

最后是MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;


public class MainActivity extends AppCompatActivity {


private RecyclerView recyclerView;
private DataAdapter dataAdapter;
private List<Datum> dataArrayList;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}


private void initViews(){
recyclerView=(RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
loadJSON();
}


private void loadJSON(){
dataArrayList = new ArrayList<>();
Retrofit retrofit=new Retrofit.Builder().baseUrl("https://www.whitehouse.gov/").addConverterFactory(GsonConverterFactory.create()).build();
RequestInterface requestInterface=retrofit.create(RequestInterface.class);
Call<List<Datum>> call= requestInterface.getJSON();
call.enqueue(new Callback<List<Datum>>() {
@Override
public void onResponse(Call<List<Datum>> call, Response<List<Datum>> response) {
dataArrayList = response.body();
dataAdapter=new DataAdapter(getApplicationContext(),dataArrayList);
recyclerView.setAdapter(dataAdapter);
}


@Override
public void onFailure(Call<List<Datum>> call, Throwable t) {
Log.e("Error",t.getMessage());
}
});
}
}

你需要让Gson知道你回复的其他类型如下

import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;




Type collectionType = new TypeToken<List<UserSite>>(){}.getType();
List<UserSite> userSites  = gson.fromJson( response.getBody() , collectionType);

我不确定这是否是使用GSON的最佳方式,但对我来说是可行的。你可以在MainActivity上使用这样的语句:

 public void readJson() {
dataArrayList = new ArrayList<>();
String json = "[\n" + IOHelper.getData(this) + "\n]\n";
Log.d(TAG, json);
try{
JSONArray channelSearchEnums = new JSONArray(json);


for(int i=0; i< channelSearchEnums.length(); i++)
{
JSONObject enum = channelSearchEnums.getJSONObject(i);
ChannelSearchEnum channel = new ChannelSearchEnum(
enum.getString("updated_at"), enum.getString("fetched_at"),
enum.getString("description"), enum.getString("language"),
enum.getString("title"), enum.getString("url"),
enum.getString("icon_url"), enum.getString("logo_url"),
enum.getString("id"), enum.getString("modified"))


dataArrayList.add(channel);
}


//The code and place you want to show your data


}catch (Exception e)
{
Log.d(TAG, e.getLocalizedMessage());
}
}

你只有字符串,但如果你有双精度或int,你也可以放getDoublegetInt

IOHelper类的方法是next(这里,路径保存在内部存储器上):

 public static String getData(Context context) {
try {
File f = new File(context.getFilesDir().getPath() + "/" + fileName);
//check whether file exists
FileInputStream is = new FileInputStream(f);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer);
} catch (IOException e) {
Log.e("TAG", "Error in Reading: " + e.getLocalizedMessage());
return null;
}
}

如果你想了解更多信息,你可以看到这个视频,在那里我得到了readJson()的代码;和这个线程,在那里我得到了getData()的代码。

这看起来像一个Json数组列表。因此,最好使用ArrayList来处理数据。在你的api端点添加这样的数组列表

 @GET("places/")
Call<ArrayList<Place>> getNearbyPlaces(@Query("latitude") String latitude, @Query("longitude") String longitude);

芬兰湾的科特林:

var list=ArrayList<Your class name>()
val listresult: Array<YOUR CLASS NAME> = Gson().fromJson(
YOUR JSON RESPONSE IN STRING,
Array<Your class name>:: class.java)


list.addAll(listresult)
public ChannelSearchEnum[] getChannelSearchEnum(Response response) {
return response.as(ChannelSearchEnum[].class, ObjectMapperType.GSON);
}

上面将解决和传递响应将返回类的映射对象数组

解决方案

  1. 我正在使用截击库。我解析响应自动在凌空使用GSON

[
{
"name": "Naruto: Shippuuden",
"description": "It has been two and a half years since Naruto Uzumaki left Konohagakure, the Hidden Leaf Village, for intense training following events which fueled his desire to be stronger. Now Akatsuki, the mysterious organization of elite rogue ninja, is closing in on their grand plan which may threaten the safety of the entire shinobi world.",
"Rating": "8.16",
"episode": 500,
"categorie":"Animation | Drama | Adventure",
"studio":"Studio Pierrot",
"img": "https://myanimelist.cdn-dena.com/images/anime/5/17407.jpg"
},
{
"name": "One Piece",
"description": "Gol D. Roger was known as the 'Pirate King',the strongest and most infamous being to have sailed the Grand Line. The capture and death of Roger by the World Government brought a change throughout the world. His last words before his death revealed the existence of the greatest treasure in the world, One Piece. It was this revelation that brought about the Grand Age of Pirates, men who dreamed of finding One Piece—which promises an unlimited amount of riches and fame—and quite possibly the pinnacle of glory and the title of the Pirate King.",
"Rating": "8.54",
"episode": 700,
"categorie":"Animation | Drama | Adventure",
"studio":"Toei Animation",
"img": "https://myanimelist.cdn-dena.com/images/anime/6/73245.jpg"
}
]


2.这是我的模型


public class DataResponse implements Serializable {
    

@SerializedName("studio")
private String studio;
    

@SerializedName("img")
private String img;
    

@SerializedName("categorie")
private String categorie;
    

@SerializedName("Rating")
private String rating;
    

@SerializedName("name")
private String name;
    

@SerializedName("description")
private String description;
    

@SerializedName("episode")
private int episode;
    

public void setStudio(String studio){
this.studio = studio;
}
    

public String getStudio(){
return studio;
}
    

public void setImg(String img){
this.img = img;
}
    

public String getImg(){
return img;
}
    

public void setCategorie(String categorie){
this.categorie = categorie;
}
    

public String getCategorie(){
return categorie;
}
    

public void setRating(String rating){
this.rating = rating;
}
    

public String getRating(){
return rating;
}
    

public void setName(String name){
this.name = name;
}
    

public String getName(){
return name;
}
    

public void setDescription(String description){
this.description = description;
}
    

public String getDescription(){
return description;
}
    

public void setEpisode(int episode){
this.episode = episode;
}
    

public int getEpisode(){
return episode;
}
    

@Override
public String toString(){
return
"Response{" +
"studio = '" + studio + '\'' +
",img = '" + img + '\'' +
",categorie = '" + categorie + '\'' +
",rating = '" + rating + '\'' +
",name = '" + name + '\'' +
",description = '" + description + '\'' +
",episode = '" + episode + '\'' +
"}";
}
}


  1. 我的API方法
define globle


private List<DataResponse> dataResponses = new ArrayList<>();



private void volleyAutomation(String url) {
JSONArray array = new JSONArray();
JsonArrayRequest request_json = new JsonArrayRequest(Request.Method.GET, url, array,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
    

GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
dataResponses = Arrays.asList(gson.fromJson(response.toString(), DataResponse[].class));
    

rvList(dataResponses);
Log.d("respknce___", String.valueOf(dataResponses.size()));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
    

}
});
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
requestQueue.add(request_json);
}