GSON wirft "Erwartetes BEGIN_OBJECT, aber war BEGIN_ARRAY"?


295

Ich versuche, eine JSON-Zeichenfolge wie diese zu analysieren

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

in eine Liste von Objekten.

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

Hier ist eine Objektklasse, die ich verwende.

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

        }

Aber es wirft mich mit

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

Irgendwelche Ideen, wie ich das beheben soll?


12
@Soni - das ist falsch. Wenn Sie zu jsonlint.org gehen und seinen JSON kopieren / einfügen, werden Sie sehen, dass er gültig ist.
Brian Roach

@Soni - nein, "[" und "]" entfernt, aber immer noch gleich. Ich denke, es könnte mehr sein, weil die Zeichenfolge, die ich habe, mehrere Objekte enthält, nicht nur eines.
Roger Travis

Wie sieht dein jstringAussehen aus, auf das du in deinem Code angespielt hast?
IgorGanapolsky

Ich beobachte einen Gedanken, wenn die Antwort im Array zurückkehrt und dann versucht, List aufzunehmen, löst dies mein Problem.
iamkdblue

Antworten:


331

Das Problem ist, dass Sie erzählen Gson Sie ein Objekt Ihres Typs haben. Das tust du nicht. Sie haben eine Reihe von Objekten Ihres Typs. Sie können nicht einfach versuchen, das Ergebnis so zu wirken und erwarten, dass es magisch funktioniert;)

Das Benutzerhandbuch für GsonErklärt, wie Sie damit umgehen:

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

Das wird funktionieren:

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

Aber das ist besser:

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

wahrscheinlich in der Tat. Als Array von Objekten wird der Typ zur Laufzeit beibehalten, damit gson weiß, wonach er suchen muss. gute Idee.
NJZK2

3
+1 für TypoToken<Collection<Something>>- Verwenden Sie keine Arrays, wenn Sie Collection (Unterklassen) und / oder Iterables haben können.
Philipp Reichart

Halten Sie es für die richtige Methode, um ausgewählte Objekte / Arrays zu analysieren? Hilfe stackoverflow.com/questions/18140830/…
LOG_TAG

1
Was ist, wenn wir es mit String machen wollen? Zum Beispiel kann ich so etwas wie String [] t = gson.fromJson (myJson, String []. Class)
schreiben

4
Das Gefühl, diese Antwort ist unvollendet !!
EngineSense

45

Das Problem ist, dass Sie nach einem Objekt vom Typ fragen, ChannelSearchEnumaber was Sie tatsächlich haben, ist ein Objekt vom TypList<ChannelSearchEnum> .

Sie können dies erreichen mit:

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

1
Was Typeist das? was importieren?
smatthewenglish

4
@ S.Matthew_English höchstwahrscheinlichjava.lang.reflect.Type
Guillaume Polet

36

In meinem Fall JSON-Zeichenfolge:

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

und ich drucke "Kategorie" und "url_title" in recycleview

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

und schließlich 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
beste Antwort für solche Probleme
Nicky Manali

4
Dies beantwortet die Frage insbesondere für Nachrüstbenutzer perfekt. Für alle, die Klarheit suchen, ist der Teil, den Sie am meisten benötigen, Call <List <Datum >> getJSON ();
Carlos Anyona

13

Alternative könnte sein

damit Ihre Antwort so aussieht

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

anstatt

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

CODE

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

Danach wird es einfach jeder andere sein GSON Parsing


Was ist, wenn ich mein JSON-Format nicht ändern kann? Ich benutze die Gson-Anfrage von Volley, um meine Modellklasse festzulegen. Wie es geht? Danke
Kaveesh Kanwal

@KaveeshKanwal versuchen Sie andere Lösungen in diesem Thread zur Verfügung gestellt, außer diesem habe ich keine Ahnung
DeltaCap019

8

Laut GSON-Benutzerhandbuch können Sie dies nicht.

Sammlungsbeschränkungen

Kann die Sammlung beliebiger Objekte serialisieren, aber nicht deserialisieren. Weil der Benutzer den Typ des resultierenden Objekts nicht angeben kann


7
Er hat keine Sammlung willkürlicher Objekte, er hat eine Sammlung eines bestimmten Objekttyps, mit dem er Gsonsich gerne befassen wird
Brian Roach

Eigentlich habe ich wie Sie eine Antwort mit dem TypeToken geschrieben, aber da der generische Typ zur Laufzeit nicht eingebettet ist, habe ich nicht gesehen, wie das möglicherweise funktionieren könnte. (obwohl ich es nicht getestet habe).
NJZK2

3

Dies sieht aus wie eine Json-Array-Liste. Daher ist es am besten, ArrayListdie Daten zu verarbeiten. Fügen Sie in Ihrem API-Endpunkt eine Array-Liste wie diese hinzu

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

1

Sie müssen Gson den folgenden zusätzlichen Typ Ihrer Antwort mitteilen

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

Ich bin nicht sicher, ob dies der beste Weg ist, GSON zu verwenden, aber es funktioniert für mich. Sie können einige davon verwenden auf 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());
    }
}

Sie haben nur Strings, aber wenn Sie Doubles oder Int hätten, könnten Sie getDoubleoder setzengetInt auch.

Die Methode der IOHelperKlasse ist die nächste (hier wird der Pfad im internen Speicher gespeichert):

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

Wenn Sie weitere Informationen dazu wünschen, können Sie dieses Video sehen , in dem ich den Code von erhalte readJson(). und dieser Thread, in dem ich den Code von bekomme 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)

Ich habe nichts positiv oder negativ bewertet, sondern nur bearbeitet.
Shredator
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.