“预计BEGIN_OBJECT但是在第1行第1列STRING”

时间:2015-02-09 20:24:55

标签: java json parsing gson

我有这个方法:

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

18 个答案:

答案 0 :(得分:128)

即使没有看到您的JSON字符串,您也可以从错误消息中判断出它不是要解析为您的类实例的正确结构。

Gson希望你的JSON字符串以对象开始大括号开头。例如

{

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

开头
"

答案 1 :(得分:11)

来自服务器的无效JSON应始终是预期的用例。传输过程中有一百万件事可能出错。 Gson有点棘手,因为它的错误输出会给你一个问题,你捕获的实际异常将是一个不同的类型。

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

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

如果您想知道为什么从服务器收到的JSON是错误的,您可以在异常中查看catch块内部。但即使这是你的问题,也不是客户有责任修复它从互联网接收的JSON。

无论哪种方式,客户都有责任决定在JSON变坏时做什么。两种可能性是拒绝JSON并且什么都不做,并再次尝试。

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

换句话说,即使我承认它看起来不太优雅,我也会推荐

boolean failed = false;

try
{
  gson.fromJSON(ad, Ad.class);
  //...
}
catch (IllegalStateException | JsonSyntaxException exception)
{
  failed = true;
  //...
}

if (failed)
{
  //...

答案 2 :(得分:3)

在Retrofit2中,如果要以raw格式发送参数,则必须使用标量。

首先在你的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) {
    }
}

参考:[How to POST raw whole JSON in the body of a Retrofit request?

答案 3 :(得分:3)

在我的情况下,我有一个“模型”,由几个String参数组成,但一个除外:它是字节数组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));
    }
}

要将JSONObject转换为模型,我使用了以下内容:

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

代码的作用基本上是在到/来回JSONObject的转换过程中遇到的class/object(在本例中为byte[]类)中通过Adapter进行推送。

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

我来分享一个解决方案。迫使Notbook挂断后,错误发生在我身上。可能的解决方案clean preject

答案 6 :(得分:1)

最近我遇到了类似的问题,找到了一个有趣的解决方案。基本上,我需要将以下嵌套的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\"}}}"

我最终使用正则表达式从JSON的开头和结尾删除了引号,然后使用 apache.commons unescapeJava()方法对其进行了转义。基本上将不干净的JSON传递给以下方法以获取已清理的JSON:

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

    return StringEscapeUtils.unescapeJava(noQuotes);
}

然后使用Google GSON将其解析为我自己的对象:

MyObject myObject = new.Gson().fromJson(this.removeQuotesAndUnescape(uncleanJson));

答案 7 :(得分:0)

确保您具有DESERIALIZED对象(例如DATE / DATETIME等)。如果直接发送JSON而不进行反序列化,则可能导致此问题。

答案 8 :(得分:0)

就我而言,我将JSON对象返回为

  

{“ data”:“”,“ message”:“已保存出勤   成功.. !!!“,”状态“:”成功“}

通过将其更改为

来解决
  

{“数据”:{},“消息”:“已保存出勤   成功.. !!!“,”状态“:”成功“}

这里的数据是一个子JsonObject,它应从{而不是“”

开始

答案 9 :(得分:0)

如果您的json格式和变量都可以,请检查您的数据库查询...即使数据正确保存在db中,实际的问题也可能存在于此...重新检查您的查询并重试。希望对您有帮助

答案 10 :(得分:0)

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

答案 11 :(得分:0)

别忘了先使用Gson()将对象转换为Json

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

然后,您可以使用这个很棒的库轻松地将其转换回对象

      val fromUser = Gson().fromJson(fromUserJson, User::class.java)

答案 12 :(得分:0)

我遇到了从手写json文件读取的情况。 json是完美的。但是,发生此错误。因此,我从一个Java对象写入json文件,然后从该json文件读取。一切都很好。我看不到手写json和来自Java对象的json之间的任何区别。尝试了超越比较,发现没有区别。 我终于注意到两个文件的大小略有不同,并且我使用了winHex工具并检测到多余的东西。 所以针对我的情况的解决方案是,复制好json文件,将内容粘贴到其中并使用。

enter image description here

答案 13 :(得分:0)

在我的情况下,我的自定义http客户端不支持gzip编码。我正在发送“ Accept-Encoding:gzip”标头,因此响应作为gzip字符串发送回,无法解码。

解决方案是不发送该标头。

答案 14 :(得分:0)

我在 Android

中使用 Retrofit 发出带有一些参数的 POST 请求

我遇到了什么:

我在 Android Studio logcat 中遇到的错误:

<块引用>

java.lang.IllegalStateException:应为 BEGIN_OBJECT 但为 STRING 在第 2 行第 1 列路径 $

[但它在 VOLLY 库中运行良好]

当我用谷歌搜索... 你知道[显然 json 期待一个 OBJECT 但是...]

但是当我改变我的服务以返回一个简单的字符串 [ 像 print_r("don't lost hope") ] 或 一点都没有

它在 Postman 中打印得很好 但在 Android Studio logcat 中,它仍然是相同的错误 [

<块引用>

java.lang.IllegalStateException:应为 BEGIN_OBJECT 但为 STRING 在第 2 行第 1 列路径 $

]

等等,我正在发送一条简单的消息或没有发送任何回复,但工作室仍然是 告诉我“...预期为 BEGIN_OBJECT 但为 STRING...” 有问题

第四天: 我终于停下来寻找“快速解决方案”并真正阅读了一些堆栈溢出问题 和文章仔细。

我得到了什么:

Logging interceptor

它会向您显示来自您的服务器的任何数据[甚至是生态消息],这些数据未显示在 Andorid工作室logcat, 这样你就可以找到问题所在。

我发现我正在使用@Body 发送数据,例如-

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

但是没有参数到达服务器,一切都是空的[我发现使用日志拦截器]

然后我简单地搜索了一篇文章“如何使用 Retrofit 发出 POST 请求” here's one

解决方案:

从这里我改变了我的方法:

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

一切都很好。

结论:

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

<块引用>

java.lang.IllegalStateException:应为 BEGIN_OBJECT 但为 STRING 在第 2 行第 1 列路径 $

完全没有意义。

所以总是详细调试,然后找到泄漏的地方,然后修复。

答案 15 :(得分: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();
                }

}

答案 16 :(得分:0)

使用带有 {} 的字符串begin & end

比如

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

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

这对我有用。

答案 17 :(得分:0)

在我的情况下,即使 Json Validator 给它一个有效的响应,对象也很好,但我使用的是这样的接口

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

一切都解决了。