Jak sprawdzić, czy podany ciąg jest prawidłowym JSON w Javie


155

Jak sprawdzić poprawność ciągu JSON w Javie? A może mógłbym przeanalizować go przy użyciu wyrażeń regularnych?


spróbować parsować z gson? sprawdzanie poprawności za pomocą wyrażenia regularnego może nie być dobrym pomysłem
aishwarya

2
Serwis json.org zawiera linki do bardzo wielu parserów
MartinK,

Odpowiedzi:


261

Dziki pomysł, spróbuj go przeanalizować i wyłap wyjątek:

import org.json.*;

public boolean isJSONValid(String test) {
    try {
        new JSONObject(test);
    } catch (JSONException ex) {
        // edited, to include @Arthur's comment
        // e.g. in case JSONArray is valid as well...
        try {
            new JSONArray(test);
        } catch (JSONException ex1) {
            return false;
        }
    }
    return true;
}

Ten kod wykorzystuje implementację JSON API org.json, która jest dostępna na github , w maven i częściowo w systemie Android .


2
Jest blisko, ale brakuje w nim walidacji dla JSONArray (zaktualizowałem ten post o bardziej odpowiednią funkcję)
Arthur

9
Wypróbowałem ciąg json, taki jak „{'hello': 'foo'} 'invalid'” (dodano „invalid” poza {}), a JSONObject nie wyrzuca ParseException. Używam org.json.JSONObject. Czy jest to oczekiwane?
Soichi Hayashi

16
Nie wspomniałeś o bibliotece, która ma JSONObject, nie widziałem jej w standardowym java lib
Krzysztof Krasoń

6
To rozwiązanie działa w większości przypadków, ale w pewnych okolicznościach może zawieść. Na przykład dopuszcza przecinek tuż przed nawiasem zamykającym, co w rzeczywistości jest błędem składniowym. Zobacz json.org/javadoc/org/json/JSONObject.html, aby zapoznać się z innymi przypadkami narożnymi.
Hua2308

9
Nie rozumiem, dlaczego plakaty nie mogą zawracać sobie głowy dołączaniem instrukcji importu z fragmentami kodu. To jest ważne. Druga ocena jest tutaj znacznie lepsza.
seansand

100

Biblioteka JACKSON

Jedną z opcji byłoby skorzystanie z biblioteki Jacksona . Najpierw zaimportuj najnowszą wersję (teraz jest):

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.0</version>
</dependency>

Następnie możesz zaimplementować poprawną odpowiedź w następujący sposób:

import com.fasterxml.jackson.databind.ObjectMapper;

public final class JSONUtils {
  private JSONUtils(){}

  public static boolean isJSONValid(String jsonInString ) {
    try {
       final ObjectMapper mapper = new ObjectMapper();
       mapper.readTree(jsonInString);
       return true;
    } catch (IOException e) {
       return false;
    }
  }
}

Opcja Google GSON

Inną opcją jest użycie Google Gson . Zaimportuj zależność:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.5</version>
</dependency>

Ponownie możesz zaimplementować proponowane rozwiązanie jako:

import com.google.gson.Gson;

public final class JSONUtils {
  private static final Gson gson = new Gson();

  private JSONUtils(){}

  public static boolean isJSONValid(String jsonInString) {
      try {
          gson.fromJson(jsonInString, Object.class);
          return true;
      } catch(com.google.gson.JsonSyntaxException ex) { 
          return false;
      }
  }
}

Oto prosty test:

//A valid JSON String to parse.
String validJsonString = "{ \"developers\": [{ \"firstName\":\"Linus\" , \"lastName\":\"Torvalds\" }, " +
        "{ \"firstName\":\"John\" , \"lastName\":\"von Neumann\" } ]}";

// Invalid String with a missing parenthesis at the beginning.
String invalidJsonString = "\"developers\": [ \"firstName\":\"Linus\" , \"lastName\":\"Torvalds\" }, " +
        "{ \"firstName\":\"John\" , \"lastName\":\"von Neumann\" } ]}";

boolean firstStringValid = JSONUtils.isJSONValid(validJsonString); //true
boolean secondStringValid = JSONUtils.isJSONValid(invalidJsonString); //false

Proszę zauważyć, że może wystąpić „drobny” problem związany z końcowymi przecinkami, który zostanie naprawiony w wydaniu 3.0.0.


Chociaż działa to w przypadku dużych rzeczy, takich jak niedopasowane cytaty lub brakujące nawiasy, Gson z radością przeanalizuje tablicę json z końcowym przecinkiem, co nie jest zgodne z RFC-4627
eurythmia

@eurythmia True! W wersji 3.0 powinni rozwiązać problem
JeanValjean

1
To również potwierdza {klucz: wartość}, ale nie jest to poprawny plik json
Pratapi Hemant Patel

2
new ObjectMapper().readTree("28xjRBuOQqupRopHeSuhRQ")Pułapka JACKSON: analizuje bez wyjątku jako IntNode (28). Niezupełnie oczekiwane ...
mgaert

1
Jak rozumiem, to rozwiązanie nie tylko weryfikuje, ale analizuje (i przechowuje) cały plik json. Konwertuje liczby na liczby całkowite / długie / podwójne itd. To jest coś więcej niż tylko sprawdzenie składni, przechowuje w pamięci cały plik json. Może to mieć znaczenie w przypadku intensywnych obciążeń. Czy istnieje lepsze rozwiązanie do sprawdzania składni?
javapowered

15

Dzięki Google Gson możesz użyć JsonParser:

import com.google.gson.JsonParser;

JsonParser parser = new JsonParser();
parser.parse(json_string); // throws JsonSyntaxException

3
Zauważ, że nie powoduje to błędu w ciągach bez nawiasów ala "asdf"
Andrew

1
Nie odrzuca też końcowych przecinków w tablicach JSON.
Sotirios Delimanolis

Naprawdę nie mogę w to ufać ... jest napisane, że ciąg „Zapisz” jest przetwarzalny.
Dherik

Uważaj, przykład gson tutaj używa łagodnego trybu parsowania, który nadal dopuszcza wiele odchyleń. Zobacz więcej szczegółów z przypadkiem testowym i przykładem ścisłej analizy w innych moich odpowiedziach.
Vadzim

14

Możesz użyć .mayBeJSON (String str) dostępnego w bibliotece JSONUtils .


tak ... to działa. Dzięki, npinti. próbowałem z gson, ale nie widziałem takiej metody.
sappu

@sappu: Jeśli ta odpowiedź rozwiązała Twoje pytanie, zaznacz je tak. Większość bibliotek ma tendencję do pobierania ciągu znaków i prób jego analizowania, jeśli analiza nie powiedzie się, to znaczy, że ciąg nie jest prawidłowym ciągiem JSON, zgłosi wyjątek.
npinti

@npinti: Dodatkowy błąd}. Zwraca prawdę dla nieprawidłowego ciągu z dodatkowym nawiasem kwadratowym =>}
Vivek

3
Ta metoda dosłownie sprawdza tylko, czy ciąg zaczyna się i kończy cudzysłowami lub nawiasami. Bardzo zawodne.
Michael Munsey

2
dlatego nazwa metody to „może”, a nie „jest” :)
Khoa

5

To zależy od tego, co próbujesz udowodnić w ramach walidacji. Z pewnością przeanalizowanie json, jak sugerowali inni, jest lepsze niż użycie wyrażeń regularnych, ponieważ gramatyka json jest bardziej skomplikowana niż można ją przedstawić za pomocą samych wyrażeń regularnych.

Jeśli json będzie kiedykolwiek analizowany tylko przez twój kod java, użyj tego samego parsera, aby go zweryfikować.

Ale samo przeanalizowanie niekoniecznie powie Ci, czy zostanie zaakceptowane w innych środowiskach. na przykład

  • wiele parserów ignoruje końcowe przecinki w obiekcie lub tablicy, ale stare wersje IE mogą zawieść, gdy trafią na końcowy przecinek.
  • Inne parsery mogą akceptować końcowy przecinek, ale dodają po nim wpis undefined / null.
  • Niektóre parsery mogą zezwalać na niecytowane nazwy właściwości.
  • Niektóre parsery mogą różnie reagować na znaki spoza ASCII w łańcuchach.

Jeśli Twoja walidacja musi być bardzo dokładna, możesz:


4
String jsonInput = "{\"mob no\":\"9846716175\"}";//Read input Here
JSONReader reader = new JSONValidatingReader();
Object result = reader.read(jsonInput);
System.out.println("Validation Success !!");

Proszę pobrać bibliotekę stringtree-json


Czy można zdefiniować String jak powyżej? Albo tylko dla Idea.
Santron Manibharathi

niemożliwe, to z powodu mojego
błędu. teraz jest

1
JSONValidatingReader nie jest częścią Java API
IgorGanapolsky

Proszę skorzystać z wyżej wymienionej biblioteki, dzięki
Jamsheer

2

Trochę o parsowaniu:

Json, a właściwie wszystkie języki, używają gramatyki, która jest zestawem reguł, których można używać jako podstawień. aby przeanalizować json, musisz w zasadzie wypracować te podstawienia w odwrotnej kolejności

Json to gramatyka bezkontekstowa , co oznacza, że ​​możesz mieć nieskończenie zagnieżdżone obiekty / tablice, a json nadal będzie prawidłowy. regex obsługuje tylko regularne gramatyki (stąd „reg” w nazwie), które są podzbiorem gramatyk bezkontekstowych, które nie pozwalają na nieskończone zagnieżdżanie, więc niemożliwe jest użycie tylko wyrażenia regularnego do przeanalizowania wszystkich prawidłowych plików json. możesz użyć skomplikowanego zestawu wyrażeń regularnych i pętli, zakładając, że nikt nie zagnieździ się powyżej, powiedzmy, 100 poziomów głębokości, ale nadal byłoby to bardzo trudne.

jeśli masz ochotę napisać swój własny parser,
możesz po opanowaniu gramatyki stworzyć rekurencyjny parser zstępujący


2

Sprawdź, czy podany ciąg jest prawidłowym JSON w Kotlinie . Przekonwertowałem odpowiedź MByD Java na Kotlin

fun isJSONValid(test: String): Boolean {
    try {
        JSONObject(test);
    } catch (ex: JSONException) {
        try {
            JSONArray(test);
        } catch (ex1: JSONException) {
            return false;
        }
    }
    return true;
}

1

Tutaj możesz znaleźć narzędzie, które może zweryfikować plik JSON lub po prostu deserializować plik JSON za pomocą dowolnej biblioteki JSON i jeśli operacja się powiedzie, to powinno być poprawne ( na przykład google-json , które wyrzuci wyjątek, jeśli dane wejściowe to analizowanie nie jest prawidłowym formatem JSON).


1

Korzystając z Playframework 2.6, można również użyć biblioteki Json znajdującej się w api Java, aby po prostu przeanalizować ciąg. Ciąg może być elementem json tablicy json. Ponieważ zwracana wartość nie ma tutaj znaczenia, po prostu przechwytujemy błąd analizy, aby określić, czy ciąg jest prawidłowym ciągiem json, czy nie.

    import play.libs.Json;

    public static Boolean isValidJson(String value) {
        try{
            Json.parse(value);
            return true;
        } catch(final Exception e){
            return false;
        }
    }

1

IMHO, najbardziej eleganckim sposobem jest użycie Java API for JSON Processing (JSON-P), jednego ze standardów JavaEE, który jest zgodny z JSR 374 .

try(StringReader sr = new StringReader(jsonStrn)) {
    Json.createReader(sr).readObject();
} catch(JsonParsingException e) {
    System.out.println("The given string is not a valid json");
    e.printStackTrace();
}

Używając Maven, dodaj zależność od JSON-P:

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1.4</version>
</dependency>

Odwiedź oficjalną stronę JSON-P, aby uzyskać więcej informacji.


1

Oto działający przykład ścisłego parsowania json z biblioteką gson :

public static JsonElement parseStrict(String json) {
    // throws on almost any non-valid json
    return new Gson().getAdapter(JsonElement.class).fromJson(json); 
}

Zobacz także moją inną szczegółową odpowiedź w artykule Jak sprawdzić, czy JSON jest poprawny w Javie przy użyciu GSON z dodatkowymi informacjami i rozszerzonym przypadkiem testowym z różnymi nieprawidłowymi przykładami.


1

Jak widać, rozwiązań jest sporo, głównie parsują one JSON, żeby to sprawdzić i na koniec trzeba będzie go przeanalizować, żeby mieć pewność.

Jednak w zależności od kontekstu można poprawić wydajność, sprawdzając wstępnie.

Kiedy wywołuję interfejsy API, po prostu sprawdzam, czy pierwszy znak to „{”, a ostatni to „}”. Jeśli tak nie jest, nie zawracam sobie głowy tworzeniem parsera.


0

Znalazłem na to bardzo proste rozwiązanie.

Najpierw zainstaluj net.sf.json-libdla niego tę bibliotekę .

    import net.sf.json.JSONException;

    import net.sf.json.JSONSerializer;

    private static boolean isValidJson(String jsonStr) {
        boolean isValid = false;
        try {
            JSONSerializer.toJSON(jsonStr);
            isValid = true;
        } catch (JSONException je) {
            isValid = false;
        }
        return isValid;
    }

    public static void testJson() {
        String vjson = "{\"employees\": [{ \"firstName\":\"John\" , \"lastName\":\"Doe\" },{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" }]}";
        String ivjson = "{\"employees\": [{ \"firstName\":\"John\" ,, \"lastName\":\"Doe\" },{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" }]}";
        System.out.println(""+isValidJson(vjson)); // true
        System.out.println(""+isValidJson(ivjson)); // false
    }

Gotowe. Cieszyć się


0

Odpowiedzi są częściowo poprawne. Ja też stanąłem przed tym samym problemem. Przetwarzanie json i sprawdzanie wyjątku wydaje się zwykłym sposobem, ale rozwiązanie nie działa w przypadku wejściowego pliku JSON, podobnie jak

{"outputValueSchemaFormat": "", "sortByIndexInRecord": 0, "sortOrder": 847874874387209 "descending"} kajhfsadkjh

Jak widać, plik json jest nieprawidłowy, ponieważ zawiera końcowe znaki śmieci. Ale jeśli spróbujesz przeanalizować powyższy json za pomocą json lub gson, otrzymasz przeanalizowaną mapę prawidłowych json, a znaki końcowe json są ignorowane. Co nie jest wymaganym rozwiązaniem, gdy używasz parsera do sprawdzania poprawności json.

Rozwiązanie tego problemu znajdziesz tutaj .

PS: To pytanie zadałem i odpowiedziałem.


0
import static net.minidev.json.JSONValue.isValidJson;

a następnie wywołaj tę funkcję, przekazując swój ciąg JSON :)


0
public static boolean isJSONValid(String test) {
    try {
        isValidJSON(test);
        JsonFactory factory = new JsonFactory();
        JsonParser parser = factory.createParser(test);
        while (!parser.isClosed()) {
            parser.nextToken();
        }
    } catch (Exception e) {
        LOGGER.error("exception: ", e);
        return false;
    }
    return true;
}

private static void isValidJSON(String test) {
    try {
        new JSONObject(test);
    } catch (JSONException ex) {
        try {
            LOGGER.error("exception: ", ex);
            new JSONArray(test);
        } catch (JSONException ex1) {
            LOGGER.error("exception: ", ex1);
            throw new Exception("Invalid JSON.");
        }
    }
}

Powyższe rozwiązanie obejmuje oba scenariusze:

  • zduplikowany klucz
  • niedopasowane cudzysłowy lub brakujące nawiasy itp.

0

Rozwiązanie wykorzystujące javax.jsonbibliotekę:

import javax.json.*;

public boolean isTextJson(String text) {
    try {
        Json.createReader(new StringReader(text)).readObject();
    } catch (JsonException ex) {
        try {
            Json.createReader(new StringReader(text)).readArray();
        } catch (JsonException ex2) {
            return false;
        }
    }
    return true;
}

0

Możesz użyć WellFormedJsonklasy z biblioteki walidacji deklaratywnej Validol .

Sama deklaracja mogłaby wyglądać następująco:

new WellFormedJson(
    new Unnamed<>(Either.right(new Present<>(jsonRequestString)))
)

Faza sprawdzania wygląda następująco:

    Result<JsonElement> result =
        (new WellFormedJson(
            new Named<>(
                "vasya",
                Either.right(
                    new Present<>(
                        "{\"guest\":{\"name\":\"Vadim Samokhin\",\"email\":\"samokhinvadim@gmail.com\"},\"source\":1,\"items\":[{\"id\":1900},{\"id\":777}]}"
                    )
                )
            )
        ))
            .result();

    assertTrue(result.isSuccessful());
    assertEquals(
        "{\"guest\":{\"name\":\"Vadim Samokhin\",\"email\":\"samokhinvadim@gmail.com\"},\"source\":1,\"items\":[{\"id\":1900},{\"id\":777}]}",
        result.value().raw().toString()
    );
    assertEquals(
        "{\"name\":\"Vadim Samokhin\",\"email\":\"samokhinvadim@gmail.com\"}",
        result.value().raw().getAsJsonObject().get("guest").toString()
    );

Może się to wydawać przesadą w przypadku tak prostego zadania, ale sprawdza się, gdy trzeba zweryfikować złożone żądanie. Sprawdź sekcję szybkiego startu validol .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.