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?

Roger Travis
quelle
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);
Brian Roach
quelle
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);
Guillaume Polet
quelle
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());
        }
    });
}
}
Shweta Chauhan
quelle
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

DeltaCap019
quelle
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

njzk2
quelle
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);
Nelson Katale
quelle
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);
Pravin
quelle
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().

PJ Alzab
quelle
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)
Abhay Kumar Bhumihar
quelle
Ich habe nichts positiv oder negativ bewertet, sondern nur bearbeitet.
Shredator