"BEGIN_OBJECT esperado, mas estava STRING na linha 1, coluna 1"

126

Eu tenho este método:

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

E eu quero analisar um JSON com:

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

Mas recebo uma mensagem de erro:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: BEGIN_OBJECT esperado, mas estava STRING na linha 1 da coluna 1

Crapo Wolf
fonte
2
Poste a sequência JSON retornada por sua solicitação de postagem.
Adrian Leonhard
Publique sua string JSON
bhspencer

Respostas:

163

Mesmo sem ver sua string JSON, você pode dizer pela mensagem de erro que não é a estrutura correta a ser analisada em uma instância da sua classe.

O Gson espera que sua string JSON comece com uma chave de abertura de objeto. por exemplo

{

Mas a cadeia que você passou para ela começa com aspas abertas

"
bhspencer
fonte
1
E o próprio nome do método sugere o porquê. parseStringToObjectsugere que ele espera um objeto JSON, que sempre começa com {.
yshavit
12
'[' indicaria o início de uma matriz Json e não de um objeto Json.
bhspencer
eu sabia disso .. mas o que temos que fazer para analisar isso?
Ajay Mistry
@AjayMistry Não está claro o que você está perguntando sem mais detalhes. Sugiro que você publique seu problema específico em uma nova pergunta com um exemplo do JSON que você está tentando analisar.
precisa saber é o seguinte
1
Caro @bhspencer Estou usando retrofit em apk android para obter um JSON simples como {"ip":"192.167.1.15"}a partir Restful EJB web service with jboss EAP 7.1do backend. No entanto, recebo "BEGIN_OBJECT esperado, mas estava STRING na linha 1 da coluna 1" Por favor, ajude-me ... Este é o meu serviço da web: @Stateless @Path ("/ getflashcard") classe pública 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; }}
Hosein Aqajani 02/04
17

JSON inválido do servidor sempre deve ser um caso de uso esperado. Um milhão de coisas podem dar errado durante a transmissão. O Gson é um pouco complicado, porque sua saída de erro fornecerá um problema e a exceção real que você capturar será de um tipo diferente.

Com tudo isso em mente, a correção adequada no lado do cliente é

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

Se você quiser saber por que o JSON que você recebeu do servidor está errado, você pode olhar dentro do seu bloco catch na exceção. Mas, mesmo que seja o seu problema, não é responsabilidade do cliente corrigir o JSON que está recebendo da Internet.

De qualquer forma, é responsabilidade do cliente decidir o que fazer quando o JSON estiver ruim. Duas possibilidades são rejeitar o JSON e não fazer nada, e tentar novamente.

Se você tentar novamente, recomendo definir um sinalizador dentro do bloco try / catch e responder a esse sinalizador fora do bloco try / catch. Provavelmente, a tentativa / captura aninhada é como o Gson nos colocou nessa confusão, com o rastreamento da pilha e as exceções não correspondentes.

Em outras palavras, mesmo admitindo que não parece muito elegante, eu recomendaria

boolean failed = false;

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

if (failed)
{
  //...
Jessica Pennell
fonte
Eu quero adicionar, pois isso está obtendo visualizações que usei um booleano para simplificar; no "mundo real", é provável que você queira testar a presença de uma cadeia de caracteres em que armazenou dados de exceção coletados em blocos individuais de tentativa / captura, repetindo essencialmente o histórico da transação para que você possa tomar decisões inteligentes quanto a se deve tentar novamente e enviar saída útil quando você finalmente decidir falhar.
Jessica Pennell
5

No Retrofit2, quando você deseja enviar seus parâmetros em bruto, deve usar escalares.

adicione primeiro no seu 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);

}

my 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", "[email protected]");
            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) {
    }
}

Referência: [ Como POST JSON inteiro bruto) no corpo de uma solicitação de Retrofit?

Raj008
fonte
3

Talvez você JSON Objectesteja certo, mas a resposta que você recebeu não é seus dados válidos. Assim como quando você conecta o inválido WiFi, você pode receber uma resposta estranha < html>.....< /html>que GSONnão pode analisar.

pode ser necessário fazer algo try..catch..para esta resposta estranha para evitar falhas.

BrantYu
fonte
3

Eu vim para compartilhar uma solução. O erro aconteceu comigo depois de forçar o caderno a desligar. solução possível clean preject.

Wallace Roberto
fonte
3

Certifique-se de ter objetos desserializados, como DATE / DATETIME etc. Se você estiver enviando diretamente JSON sem desserializá-lo, poderá causar esse problema.

Ravi Wadje
fonte
SERIALIZADO antes de enviar?
Ratzip #
@ratzip Desculpe, eu quis dizer que devemos adicionar um desserializador (lógico) para objetos como DATE | DATA HORA. Eu estava enfrentando esse problema quando queria mapear um JsonObject para um objeto JAVA.
Ravi Wadje 10/09/18
3

Na minha situação, eu tenho um "modelo", composto por vários parâmetros String, com exceção de um: é uma matriz de bytes byte[]. Algum trecho de código:

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

A última linha acima é quando o

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

é acionado. Pesquisando no SO, percebi que precisava ter alguma forma de Adapterconverter meu BaseModelJsonObject para lá e para cá. A mistura de Stringe byte[]em um modelo complica as coisas. Aparentemente, Gsonrealmente não gosto da situação.

Acabo fazendo um Adapterpara garantir que byte[]seja convertido em Base64formato. Aqui está a minha Adapterturma:

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

Para converter JSONObject em modelo, usei o seguinte:

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

Da mesma forma, para converter o modelo em JSONObject, usei o seguinte:

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

O que o código está fazendo é basicamente enviar a classe pretendida class/object(nesse caso, byte[]classe) para o momento em Adapterque for encontrada durante a conversão em / para JSONObject.

YazidEF
fonte
0

Não use jsonObject.toStringem um objeto JSON.

Solomon Fissehaye
fonte
0

No meu caso, estou retornando o objeto JSON como

{"data": "", "message": "Atendimento salvo com sucesso .. !!!", "status": "success"}

Resolvido alterando-o como

{"data": {}, "message": "Atendimento salvo com sucesso .. !!!", "status": "success"}

Aqui os dados são um sub JsonObject e devem começar em {not ""

RAJESH KUMAR ARUMUGAM
fonte
0

se o seu formato json e as variáveis ​​estiverem corretas, verifique as consultas do banco de dados ... mesmo que os dados sejam salvos no banco de dados corretamente, o problema real pode estar lá ... verifique novamente as consultas e tente novamente .. Espero que ajude

Shabbir Ahmed
fonte
0

Não se esqueça de converter seu objeto em Json primeiro usando Gson ()

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

Então você pode facilmente convertê-lo novamente em um objeto usando esta incrível biblioteca

      val fromUser = Gson().fromJson(fromUserJson, User::class.java)
Dave O Grady
fonte