"预期是BEGIN_OBJECT,但在第1行第1列是STRING"

186 人关注

我有这种方法。

public static Object parseStringToObject(String json) {
    String Object = json;
    Gson gson = new Gson();
    Object objects = gson.fromJson(object, Object.class);
    parseConfigFromObjectToString(object);
    return objects;

我想用JSON来解析。

public static void addObject(String IP, Object addObject) {
    try {
        String json = sendPostRequest("http://" + IP + ":3000/config/add_Object", ConfigJSONParser.parseConfigFromObjectToString(addObject));
        addObject = ConfigJSONParser.parseStringToObject(json);
    } catch (Exception ex) {
        ex.printStackTrace();

但我得到一个错误信息。

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 预期是BEGIN_OBJECT,但在第1行第1列是STRING。

2 个评论
Post the JSON string returned by your post request.
Post your JSON string
java
json
parsing
gson
Crapo Wolf
Crapo Wolf
发布于 2015-02-10
20 个回答
bhspencer
bhspencer
发布于 2021-09-23
已采纳
0 人赞同

即使没有看到你的JSON字符串,你也可以从错误信息中看出,它的结构不正确,不能被解析为你的类的一个实例。

Gson希望你的JSON字符串以一个对象的开头括号开始,例如

但你传递给它的字符串是以一个开放的引号开始的

这个方法的名字就说明了原因。 parseStringToObject 表明它期待一个JSON对象,它总是以 { 开头。
'['将表示一个Json数组的开始,而不是一个Json对象。
我知道......但我们要做什么来解析它呢?
@AjayMistry 如果没有更多的细节,就不清楚你在问什么。我建议在一个新问题中发布你的具体问题,并附上你试图解析的JSON的例子。
亲爱的@bhspencer 我在android apk中使用retrofit,从后台的 Restful EJB web service with jboss EAP 7.1 中获取一个简单的json,如 {"ip":"192.167.1.15"} 。但是我得到了 "Expected BEGIN_OBJECT but was STRING at line 1 column 1" Please help me...这是我的网络服务。@Stateless @Path("/getflashcard") public class GetFlashcard { @Interceptors(Validator.class) @GET @Produces(MediaType.APPLICATION_JSON) public String getFlashcard() { String jsonString = new JSONObject().put("ip", "192.167.1.15").toString(); return jsonString; }}
Jessica Pennell
Jessica Pennell
发布于 2021-09-23
0 人赞同

来自服务器的无效JSON应该始终是一个预期的用例。在传输过程中,有无数的事情会出错。Gson有点棘手,因为它的错误输出会给你一个问题,而你捕获的实际异常会是另一种类型。

考虑到所有这些,在客户端的正确修复方法是

gson.fromJSON(ad, Ad.class); //... catch (IllegalStateException | JsonSyntaxException exception) //...

如果你想知道为什么你从服务器收到的JSON是错误的,你可以在你的catch块里面看一下异常。但即使是你的问题,修复从互联网上接收的JSON也不是客户端的责任。

无论哪种方式,客户都有责任决定当它得到坏的JSON时该怎么做。有两种可能性,一是拒绝JSON,什么也不做,二是再试一次。

如果你打算再试一次,我强烈建议在try/catch块内设置一个标志,然后在try/catch块外对该标志进行响应。嵌套的try / catch很可能是Gson让我们陷入堆栈跟踪和异常不匹配的困境的原因。

换句话说,尽管我承认它看起来不是很优雅,但我还是建议

boolean failed = false;
  gson.fromJSON(ad, Ad.class);
  //...
catch (IllegalStateException | JsonSyntaxException exception)
  failed = true;
  //...
if (failed)
  //...
    
我想补充的是,由于这是在征求意见,为了简单起见,我使用了布尔值;在 "真实世界 "中,你很可能想测试是否存在一个字符串,你把收集到的异常数据存储在各个try/catch块中,基本上是向自己重放事务的历史,这样你就可以就是否重试做出明智的决定,并在最终决定失败时发送有用的输出。
Keiv
Keiv
发布于 2021-09-23
0 人赞同

我最近遇到了一个类似的问题,并找到了一个有趣的解决方案。基本上我需要将以下嵌套的JSON字符串反序列化到我的POJO中。

"{\"restaurant\":{\"id\":\"abc-012\",\"name\":\"good restaurant\",\"foodType\":\"American\",\"phoneNumber\":\"123-456-7890\",\"currency\":\"USD\",\"website\":\"website.com\",\"location\":{\"address\":{\"street\":\" Good Street\",\"city\":\"Good City\",\"state\":\"CA\",\"country\":\"USA\",\"postalCode\":\"12345\"},\"coordinates\":{\"latitude\":\"00.7904692\",\"longitude\":\"-000.4047208\"}},\"restaurantUser\":{\"firstName\":\"test\",\"lastName\":\"test\",\"email\":\"test@test.com\",\"title\":\"server\",\"phone\":\"0000000000\"}}}"

我最终使用了regex来删除JSON开头和结尾的开放引号,然后用apache.commons unescapeJava()方法来解脱它。基本上把不干净的JSON传给下面的方法,得到一个干净的。

private String removeQuotesAndUnescape(String uncleanJson) {
    String noQuotes = uncleanJson.replaceAll("^\"|\"$", "");
    return StringEscapeUtils.unescapeJava(noQuotes);

然后用Google GSON将其解析为我自己的Object。

MyObject myObject = new.Gson().fromJson(this.removeQuotesAndUnescape(uncleanJson));
    
gcr
对我来说就是这样。我把它以Gson序列化的方式发送出去,但我无法反序列化同一个实例。因此,它在传输过程中被改变了。你是否有可能使用PubNub,或者这种转义格式是一种常见的模式?
Keiv
@gcr 也许不是很常见,但我已经使用这种方法有一段时间了,没有看到任何问题。
Raj008
Raj008
发布于 2021-09-23
0 人赞同

在Retrofit2中,当你想以原始方式发送参数时,你必须使用Scalars。

首先在你的gradle中添加这个。

    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
    public interface ApiInterface {
    String URL_BASE = "http://10.157.102.22/rest/";
    @Headers("Content-Type: application/json")
    @POST("login")
    Call<User> getUser(@Body String body);

我的SampleActivity :

   public class SampleActivity extends AppCompatActivity implements Callback<User> {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ApiInterface.URL_BASE)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        ApiInterface apiInterface = retrofit.create(ApiInterface.class);
        // prepare call in Retrofit 2.0
        try {
            JSONObject paramObject = new JSONObject();
            paramObject.put("email", "sample@gmail.com");
            paramObject.put("pass", "4384984938943");
            Call<User> userCall = apiInterface.getUser(paramObject.toString());
            userCall.enqueue(this);
        } catch (JSONException e) {
            e.printStackTrace();
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
    @Override
    public void onFailure(Call<User> call, Throwable t) {

Reference: [如何在Retrofit请求的正文中发送原始的整个JSON?

Wallace Roberto
Wallace Roberto
发布于 2021-09-23
0 人赞同

我是来分享一个解决方案的。这个错误是在强迫notbook挂断后发生在我身上的。可能的解决方案 clean preject

BrantYu
BrantYu
发布于 2021-09-23
0 人赞同

也许你的 JSON Object 是正确的,但你收到的响应不是你的有效数据。就像当你连接无效的 WiFi 时,你可能会收到一个奇怪的 < html>.....< /html> GSON 无法解析。

你可能需要对这个奇怪的反应做一些 try..catch.. 以避免崩溃。

Ravi Wadje
Ravi Wadje
发布于 2021-09-23
0 人赞同

确保你有DESERIALIZED对象,如DATE/DATETIME等。如果你直接发送JSON而不进行反序列化,就会导致这个问题。

在发送之前,是否已经进行过 SERIALIZED?
@ratzip 对不起,我是说我们应该为DATE | DATETIME这样的对象添加一个反序列化器(逻辑)。当我想把一个JsonObject映射到一个JAVA对象时,我就面临这个问题。
YazidEF
YazidEF
发布于 2021-09-23
0 人赞同

在我的情况下,我有一个 "模型",由几个字符串参数组成,除了一个:它是字节数组 byte[] 。 一些代码片段。

String response = args[0].toString();
Gson gson = new Gson();
BaseModel responseModel = gson.fromJson(response, BaseModel.class);

上面的最后一行是当

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column

被触发了。通过搜索SO,我意识到我需要有某种形式的Adapter来把我的BaseModel转换成JsonObject。在一个模型中混合使用Stringbyte[]确实使事情变得复杂。很明显,Gson并不喜欢这种情况。

我最后做了一个Adapter来确保byte[]被转换为Base64的格式。下面是我的Adapter类。

public class ByteArrayToBase64Adapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
    @Override
    public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return Base64.decode(json.getAsString(), Base64.NO_WRAP);
    @Override
    public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(Base64.encodeToString(src, Base64.NO_WRAP));

To convert JSONObject to model, I used the following:

Gson customGson = new GsonBuilder().registerTypeHierarchyAdapter(byte[].class, new ByteArrayToBase64Adapter()).create();
BaseModel responseModel = customGson.fromJson(response, BaseModel.class);

同样地,为了将模型转换为JSONObject,我使用了以下方法。

Gson customGson = new GsonBuilder().registerTypeHierarchyAdapter(byte[].class, new ByteArrayToBase64Adapter()).create();
String responseJSon = customGson.toJson(response);

代码所做的基本上是通过Adapter推送预期的class/object(在本例中是byte[]类),只要在转换到/从JSONObject的过程中遇到了它。

Solomon Fissehaye
Solomon Fissehaye
发布于 2021-09-23
0 人赞同

不要在JSON对象上使用 jsonObject.toString

RAJESH KUMAR ARUMUGAM
RAJESH KUMAR ARUMUGAM
发布于 2021-09-23
0 人赞同

在我的案例中,我正在返回JSON对象作为

{"data":"", "message": "Attendance Saved. 成功!!!", "状态": "成功"}

解决的方法是把它改成

{"数据":{}, "信息": "出席率已保存。 成功!!!", "状态": "成功"}

这里的数据是一个子JsonObject,它应该从{开始,而不是""

dave o grady
dave o grady
发布于 2021-09-23
0 人赞同

Don't forget to convert your object into Json first using Gson()

  val fromUserJson = Gson().toJson(notificationRequest.fromUser)

然后你可以使用这个很棒的库轻松地将其转换为一个对象

      val fromUser = Gson().fromJson(fromUserJson, User::class.java)
    
Shabbir Ahmed
Shabbir Ahmed
发布于 2021-09-23
0 人赞同

如果你的json格式和变量没有问题,那么请检查你的数据库查询......即使数据正确地保存在数据库中,实际问题也可能在那里......重新检查你的查询并再次尝试。希望能有所帮助

Feng Zhang
Feng Zhang
发布于 2021-09-23
0 人赞同

我有一个案例,我从一个手写的json文件中读取。json是完美的。然而,发生了这个错误。所以我从一个java对象写到json文件,然后从这个json文件中读出。事情很好。我看不出手写的json和来自java对象的json有什么不同。我试过beyondCompare,它也没有看到任何区别。 我终于注意到这两个文件的大小略有不同,我用winHex工具检测了额外的东西。 所以针对我的情况的解决方案是,复制好的json文件,把内容粘贴到其中,然后使用。

elliptic1
elliptic1
发布于 2021-09-23
0 人赞同

在我的例子中,我的自定义http-client不支持gzip编码。我发送了 "Accept-Encoding: gzip "头,所以响应被作为gzip字符串发送回来,无法被解码。

解决办法是不发送该标头。

Makarand
Makarand
发布于 2021-09-23
0 人赞同

我在做一个带有一些参数的POST请求,使用的是 Retrofit in 安卓

我所面临的情况。

The error I was getting in 安卓 Studio logcat:

java.lang.IllegalStateException。预期是BEGIN_OBJECT但却是STRING 在第2行第1列路径$

[但使用VOLLY库时,它工作得很好] 。

当我在谷歌上搜索时... 你知道[显然json是在期待一个OBJECT,但是......] 。

但是,当我把我的服务改为返回一个简单的字符串[如print_r("don't lose hope") ] 或 完全没有注意到

It was getting printed fine in Postman but in 安卓 studio logcat, it was still SAME ERROR [

java.lang.IllegalStateException。 预期是BEGIN_OBJECT但却是STRING 在第2行第1列路径$

等一下,我正在发送一个简单的信息或不发送任何响应,但工作室仍然 告诉我"......期望是BEGIN_OBJECT但却是STRING......" 有什么问题吗?

在第四天。 我终于停止了寻找 "快速解决方案",真正阅读了一些堆栈溢出的问题

我得到了什么。

Logging interceptor

它将显示来自你的服务器的任何数据[甚至是生态信息],这些数据在 Andorid studios logcat中没有显示的数据。 这样你就可以找到问题所在了。

我发现我是用@Body来发送数据的,比如说

@Headers("Content-Type: application/json")
@POST("CreateNewPost")
Call<Resp> createNewPost(@Body ParaModel paraModel);

但没有任何参数到达服务器,所有的东西都是空的[我用日志拦截器发现的]

然后我简单地搜索了一篇文章 "如何使用Retrofit进行POST请求" here's one

SOLUTION:

从这里我把我的方法改成了。

@POST("CreateNewPost")
@FormUrlEncoded
Call<Resp> createNewPost(
    @Field("user_id") Integer user_id,
    @Field("user_name") String user_name, 
    @Field("description") String description,
    @Field("tags") String tags);

而且一切都很好。

CONCLUSION:

我不明白为什么Retrofit会出现这个错误

java.lang.IllegalStateException。预期是BEGIN_OBJECT但却是STRING 在第2行第1列路径$

这根本就没有任何意义。

所以一定要详细地调试,然后找到哪里有问题,再进行修复。

Sachidanand Pandit
Sachidanand Pandit
发布于 2021-09-23
0 人赞同
This error solved for by replacing .toString method to .string on the response
toString => string (add in try{...code..}catche(IOException e))
below code is working for me 
try {
     MainModelResponse model;
     Gson gson = new GsonBuilder().create();
     if (response.code() == ConstantValues.SUCCESS_OK) {
         model = gson.fromJson(response.body().string(), MainModelResponse.class);
     } else {
       model = gson.fromJson(response.errorBody().string(), MainModelResponse.class);
                    moduleData.postValue(model);
                }catch (IllegalStateException | JsonSyntaxException | IOException exception){
                    exception.printStackTrace();
    
B.Kingsun
B.Kingsun
发布于 2021-09-23
0 人赞同

用字符串 begin & end with {}.

final String jsStr = "{\"metric\":\"opentsdb_metric\",\"tags\":{\"testtag\":\"sunbotest\"},\"aggregateTags\":[],\"dps\":{\"1483399261\":18}}";

DataPoint dataPoint = new Gson().fromJson(jsStr, DataPoint.class);

this works for me.

Faizan Haidar Khan
Faizan Haidar Khan
发布于 2021-09-23
0 人赞同

在我的案例中,对象都很好,甚至是 Json验证器 是给它一个有效的回应,但我是这样使用界面的

@POST(NetworkConstants.REGISTER_USER)
Call<UserResponse> registerUser(
        @Query("name") String name,
        @Query("email") String email,
        @Query("password") String password,
        @Query("created_date") Long creationDate

然后我把代码改为

@FormUrlEncoded
@POST(NetworkConstants.REGISTER_USER)
Call<UserResponse> registerUser(
        @Field("name") String name,
        @Field("email") String email,
        @Field("password") String password,
        @Field("created_date") Long creationDate

而一切都得到了解决。

amir.ashrafi
amir.ashrafi
发布于 2021-09-23
0 人赞同

我的问题与我的代码无关

从另一个项目中复制了一些文件后,出现了这个问题

在堆栈中指向Gson库的

in 和roid studio 4.2.1 this problem not solved when I try file-> invalidate 和 restart

重新启动后,在第一次构建时得到了同样的错误,但在第二次构建时这个问题得到了解决。

I don't underst和 why this happened

ali sampson
ali sampson
发布于 2021-09-23
0 人赞同

我使用的是旧版本的 retrofit 库。因此,我必须做的是在升级到 com.squareup.retrofit2:retrofit:2.9.0 之后,将我的代码从这上面改掉。

@POST(AppConstants.UPLOAD_TRANSACTION_DETAIL)
fun postPremiumAppTransactionDetail(
   @Query("name") planName:String,
   @Query("amount") amount:String,
   @Query("user_id") userId: String,
   @Query("sub_id") planId: String,
   @Query("folder") description:String,
   @Query("payment_type") paymentType:String):
Call<TransactionResponseModel>

To this:

@FormUrlEncoded
@POST(AppConstants.UPLOAD_TRANSACTION_DETAIL)
fun postPremiumAppTransactionDetail(
   @Field("name") planName:String,
   @Field("amount") amount:String,
   @Field("user_id") userId: String,