GSON ném ném được mong đợi BEGIN_OB DỰ ÁN nhưng là BEGIN_ARRAY?


295

Tôi đang cố phân tích một chuỗi JSON như thế này

[
   {
      "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"
   }
]

vào một danh sách các đối tượng.

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

Đây là một lớp đối tượng tôi đang sử dụng.

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;
}

        }

Nhưng nó ném tôi với

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

Bất kỳ ý tưởng làm thế nào tôi nên sửa chữa nó?


12
@Soni - đó là không chính xác. Nếu bạn truy cập jsonlint.org và sao chép / dán JSON của anh ấy, bạn sẽ thấy rằng nó hợp lệ.
Brian Roach

@Soni - không, loại bỏ "[" và "]", nhưng vẫn như vậy. đoán nó có thể nhiều hơn bởi vì chuỗi tôi có chứa nhiều đối tượng, không chỉ một.
Roger Travis

Bạn jstringtrông như thế nào mà bạn đã ám chỉ trong mã của mình?
IgorGanapolsky

Tôi quan sát một suy nghĩ, khi phản hồi trở lại trong mảng rồi thử đưa vào Danh sách, nó giải quyết vấn đề của tôi.
iamkdblue

Câu trả lời:


331

Vấn đề là bạn đang nói rằng Gsonbạn có một đối tượng thuộc loại của bạn. Bạn không. Bạn có một loạt các đối tượng của loại hình của bạn. Bạn không thể thử và đưa ra kết quả như thế và mong đợi nó hoạt động một cách kỳ diệu;)

Hướng dẫn sử dụng để Gsongiải thích cách xử lý vấn đề này:

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

Điều này sẽ làm việc:

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

Nhưng điều này tốt hơn:

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

có lẽ thực sự là một mảng của đối tượng, kiểu được giữ lại trong thời gian chạy để gson biết những gì cần tìm. ý tưởng tốt.
njzk2

3
+1 cho TypoToken<Collection<Something>>- không sử dụng mảng khi bạn có thể có Bộ sưu tập (lớp con) và / hoặc Iterables.
Philipp Reichart

Bạn có nghĩ rằng đó là phương pháp đúng để phân tích obj / mảng đã chọn không? trợ giúp stackoverflow.com/questions/18140830/ từ
LOGiah

1
Điều gì nếu chúng ta muốn làm cho nó với chuỗi; Ví dụ: tôi có thể viết một cái gì đó như String [] t = gson.fromJson (myJson, String []. Class)
Sahin Yanlık

4
Cảm thấy câu trả lời này là dang dở !!
EngineSense

45

Vấn đề là bạn đang yêu cầu một đối tượng loại ChannelSearchEnumnhưng những gì bạn thực sự có là một đối tượng của loại List<ChannelSearchEnum>.

Bạn có thể đạt được điều này với:

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

1
đó Typelà cái gì Nhập gì?
smatthewenglish

4
@ S.Matthew_English rất có thểjava.lang.reflect.Type
Guillaume Polet

36

Trong trường hợp của tôi, chuỗi 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"}]

và tôi in "danh mục" và "url_title" trong tái chế

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;
}

}

Yêu cầu đối mặt

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();
}

DataAd CHƯƠNG

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);
    }
}
}

và cuối cùng là 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());
        }
    });
}
}

5
câu trả lời tốt nhất cho loại vấn đề như vậy
Nicky Manali

4
Điều này hoàn toàn trả lời câu hỏi đặc biệt là cho người dùng trang bị thêm. Đối với bất kỳ ai tìm kiếm sự rõ ràng, phần bạn cần nhất là Gọi <Danh sách <Datum >> getJSON ();
Carlos Anyona 18/03/19

13

Thay thế có thể là

để làm cho phản ứng của bạn trông giống như

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"
   }
]
}

thay vì

máy chủ_JRRRonse

[
   {
      "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);

Sau này nó sẽ chỉ là bất kỳ GSON Parsing


Nếu tôi không thể thay đổi định dạng json thì sao? Tôi đang sử dụng yêu cầu gson của bóng chuyền để thiết lập lớp mô hình của mình. Làm thế nào để làm nó? Cảm ơn
Kaveesh Kanwal

@KaveeshKanwal thử các giải pháp khác được cung cấp trong chuỗi này, ngoài điều này tôi không biết
DeltaCap019

8

theo hướng dẫn sử dụng GSON , bạn không thể.

Giới hạn bộ sưu tập

Có thể tuần tự hóa bộ sưu tập các đối tượng tùy ý nhưng không thể giải tuần tự từ nó. Bởi vì không có cách nào để người dùng chỉ ra loại đối tượng kết quả


7
Anh ta không có một bộ sưu tập các đối tượng tùy ý, anh ta có một bộ sưu tập một loại đối tượng cụ thểGson sẽ vui vẻ đối phó
Brian Roach

Trên thực tế, tôi đã bắt đầu bằng cách viết câu trả lời với TypeToken giống như bạn đã làm, nhưng vì loại chung không được nhúng trong thời gian chạy, tôi không thấy cách đó có thể hoạt động. (mặc dù tôi đã không kiểm tra nó).
njzk2

3

Điều này trông giống như một danh sách mảng Json. Vì vậy, tốt nhất nên sử dụng ArrayListđể xử lý dữ liệu. Trong điểm cuối api của bạn thêm danh sách mảng như thế này

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

1

Bạn cần cho Gson biết loại phản hồi bổ sung của bạn như dưới đây

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);

1

Tôi không chắc đây có phải là cách tốt nhất để sử dụng GSON hay không, nhưng hiệu quả với tôi. Bạn có thể sử dụng một số như thế này trên 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());
    }
}

Bạn chỉ có chuỗi, nhưng nếu bạn có gấp đôi hoặc int, bạn có thể đặt getDoublehoặc getIntquá.

Phương thức của IOHelperlớp là tiếp theo (Ở đây, đường dẫn được lưu trên Bộ nhớ trong):

 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;
    }
}

Nếu bạn muốn biết thêm thông tin về điều này, bạn có thể xem video này , nơi tôi lấy mã của readJson(); và chủ đề này , nơi tôi nhận được mã của getData().


0

Kotlin:

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)

Tôi không upvote hay downvote bất cứ điều gì, chỉ chỉnh sửa.
Máy hủy tài liệu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.