web-dev-qa-db-fra.com

Comment vérifier si JSON est valide en Java avec GSON?

J'ai méthode qui doit vérifier si JSON est valide, trouvé sur Comment vérifier si une chaîne donnée est valide JSON en Java mais cela ne fonctionne pas.

public static boolean isJson(String Json) {
        Gson gson = new Gson();
        try {
            gson.fromJson(Json, Object.class);
            return true;
        } catch (com.google.gson.JsonSyntaxException ex) {
            return false;
        }
    }

Si j'utilise cette méthode avec une chaîne, elle retourne toujours true. Par exemple:

System.out.println(renderHtml.isJson("{\"status\": \"UP\"}"));

cela m'a donné true, et

System.out.println(renderHtml.isJson("bncjbhjfjhj"));

m'a donné true également.

7
QkiZ

J'ai trouvé la solution mais en utilisant la bibliothèque org.json, selon Comment vérifier si une chaîne donnée est valide JSON en Java

public static boolean isJson(String Json) {
        try {
            new JSONObject(Json);
        } catch (JSONException ex) {
            try {
                new JSONArray(Json);
            } catch (JSONException ex1) {
                return false;
            }
        }
        return true;
    }

Maintenant, la chaîne aléatoire bncjbhjfjhj est false et {"status": "UP"} est vraie.

3
QkiZ

Bien que cela puisse vous paraître bizarre 

"bncjbhjfjhj"

Est en effet valide json, car c’est une chaîne, et c’est la seule chaîne.

Selon le pas si nouveau JSON RFC

Un texte JSON est une valeur sérialisée. Notez que certains précédents les spécifications de JSON ont contraint un texte JSON à être un objet ou un tableau. Les mises en œuvre qui génèrent uniquement des objets ou des tableaux où un Le texte JSON appelé est interopérable en ce sens que tout les implémentations les accepteront comme textes JSON conformes.

8
WilomGfx

Vous ne devez pas utiliser Gson pour effectuer cette validation:

  • Gson est un objet qui exécute désérialisation et par conséquent il désérialise entier JSON sous forme d'objet en mémoire.
  • Gson, et je ne le savais pas, n'est peut-être pas très strict pour certains JSON non valides: bncjbhjfjhj est désérialisé en tant qu'instance Java.lang.String. Surprise Surprise!
private static final Gson gson = new Gson();

private static final String VALID_JSON = "{\"status\": \"UP\"}";
private static final String INVALID_JSON = "bncjbhjfjhj";

System.out.println(gson.fromJson(VALID_JSON, Object.class).getClass());
System.out.println(gson.fromJson(INVALID_JSON, Object.class).getClass());

Sortie:

classe com.google.gson.internal.LinkedTreeMap
classe Java.lang.String 

Ce que vous pouvez faire ici, c'est utiliser JsonReader pour lire le jeton JSON entrant par jeton, ce qui permet de déterminer si le document JSON donné est syntaxiquement valide.

private static boolean isJsonValid(final String json)
        throws IOException {
    return isJsonValid(new StringReader(json));
}

private static boolean isJsonValid(final Reader reader)
        throws IOException {
    return isJsonValid(new JsonReader(reader));
}

private static boolean isJsonValid(final JsonReader jsonReader)
        throws IOException {
    try {
        JsonToken token;
        loop:
        while ( (token = jsonReader.peek()) != END_DOCUMENT && token != null ) {
            switch ( token ) {
            case BEGIN_ARRAY:
                jsonReader.beginArray();
                break;
            case END_ARRAY:
                jsonReader.endArray();
                break;
            case BEGIN_OBJECT:
                jsonReader.beginObject();
                break;
            case END_OBJECT:
                jsonReader.endObject();
                break;
            case NAME:
                jsonReader.nextName();
                break;
            case STRING:
            case NUMBER:
            case BOOLEAN:
            case NULL:
                jsonReader.skipValue();
                break;
            case END_DOCUMENT:
                break loop;
            default:
                throw new AssertionError(token);
            }
        }
        return true;
    } catch ( final MalformedJsonException ignored ) {
        return false;
    }
}

Et puis testez-le:

System.out.println(isJsonValid(VALID_JSON));
System.out.println(isJsonValid(INVALID_JSON));

Sortie:

vrai
faux 

4

Une autre option consiste à appliquer des post-vérifications personnalisées à l'objet json de niveau supérieur, comme suit:

import org.junit.Test;
import com.google.gson.*;
import static org.junit.Assert.*;

public class JsonTest {

    private JsonObject parse(@Nonnull String json) throws JsonSyntaxException {
        JsonElement res = new JsonParser().parse(json);
        System.out.println(res);
        if (!res.isJsonObject()) {
            throw new JsonSyntaxException("Top level JSON object required");
        }
        return res.getAsJsonObject();
    }

    private static void assertThrows(Runnable r) {
        try {
            r.run();
            fail();
        } catch (JsonSyntaxException expected) {
            // ok
        }
    }

    @Test
    public void testIt() {
        assertThrows(() -> parse(""));
        assertThrows(() -> parse("null"));
        assertThrows(() -> parse("Abracadabra"));
        assertThrows(() -> parse("[]"));
        assertTrue(parse("{}").entrySet().isEmpty());
        assertThrows(() -> parse("{a: }"));
        assertThrows(() -> parse("{a: ,}"));
        assertThrows(() -> parse("{a: 0,}"));
        assertTrue(parse("{a: null}").get("a").isJsonNull());
        assertEquals(0, parse("{a: 0}").get("a").getAsInt());
        assertEquals("", parse("{a: ''}").get("a").getAsString());
        assertEquals("", parse("{a: \"\"}").get("a").getAsString());
        assertEquals(0, parse("{a: []}").get("a").getAsJsonArray().size());
        //assertThrows(() -> parse("{a: [1,]}")); // TODO: this parses without error to {"a":[1,null]}
    }

}
0
Vadzim