web-dev-qa-db-fra.com

Java/Android - Valider le JSON de chaîne par rapport au schéma de chaîne

Je ne parviens pas à trouver le moyen le plus simple de valider une chaîne JSON par rapport à une chaîne de schéma JSON donnée (pour référence, elle est en Java et s'exécute dans une application Android). 

Dans l'idéal, j'aimerais simplement passer une chaîne JSON et une chaîne de schéma JSON, et cela renvoie un booléen indiquant si la validation a été transmise ou non. En cherchant, j'ai trouvé les 2 bibliothèques prometteuses suivantes pour accomplir ceci:

http://jsontools.berlios.de/

https://github.com/fge/json-schema-validator

Cependant, le premier semble assez obsolète avec un support médiocre. J'ai implémenté la bibliothèque dans mon projet et, même avec leurs JavaDocs, je ne savais pas comment construire correctement un objet "Validator" à des fins de validation.

Histoire similaire avec le deuxième, qui semble être à jour avec un bon code de test. Cependant, pour ce que je veux faire, ce qui est très simple, cela semble un peu déconcertant et déroutant de savoir comment accomplir spécifiquement ce que je veux (même après avoir examiné le fichier ValidateServlet.Java ). 

Curieux si quelqu'un a d'autres suggestions sur un bon moyen d'y parvenir (d'après ce qu'il semble), une tâche simple qui en a besoin, ou si j'ai peut-être besoin de m'en tenir à la deuxième option ci-dessus? Merci d'avance!

16
svguerin3

C'est essentiellement ce que fait le Servlet auquel vous êtes lié. Ce n'est donc peut-être pas un one-liner mais il reste expressif.

useV4 et useId tels que spécifiés sur le servlet servent à spécifier l'option de validation pour Default to draft v4 et Use id for addressing

Vous pouvez le voir en ligne: http://json-schema-validator.herokuapp.com/

public boolean validate(String jsonData, String jsonSchema, boolean useV4, boolean useId) throws Exception {
   // create the Json nodes for schema and data
   JsonNode schemaNode = JsonLoader.fromString(jsonSchema); // throws JsonProcessingException if error
   JsonNode data = JsonLoader.fromString(jsonData);         // same here

   JsonSchemaFactory factory = JsonSchemaFactories.withOptions(useV4, useId);
   // load the schema and validate
   JsonSchema schema = factory.fromSchema(schemaNode);
   ValidationReport report = schema.validate(data);

   return report.isSuccess();
}
10
Alex

Un merci reconnaissant à Douglas Crockford et Francis Galiegue d’avoir écrit le processeur de schéma json basé sur Java! Et le testeur en ligne à http://json-schema-validator.herokuapp.com/index.jsp est génial! J'aime beaucoup les messages d'erreur utiles (j'ai trouvé seulement un exemple dans lequel ils ont échoué), bien que ligne et colonne et/ou contexte soient encore meilleurs (pour le moment, vous n'obtenez que des informations sur les lignes et les colonnes lors d'erreurs de format JSON (avec la permission de Jackson Enfin, je voudrais remercier Michael Droettboom pour son tutoriel great (même s’il ne couvrait que Python, Ruby et C tout en ignorant visiblement le meilleur langage :-)).

Pour ceux qui l'ont manqué (comme je l'ai fait au début), vous trouverez des exemples à l'adresse github.com/fge/json-schema-processor-exemples. Bien que ces exemples soient très impressionnants, ils ne sont pas les simples exemples de validation JSON qui avaient été demandés à l’origine (et que je recherchais moi aussi). Les exemples les plus simples sont à l'adresse github.com/fge/json-schema-validator/blob/master/src/main/Java/com/github/fge/jsonschema/examples/Example1.Java.

Le code d'Alex ci-dessus ne fonctionnait pas pour moi, mais était très utile. mon pom extrait la dernière version stable, la version 2.0.1, avec la dépendance suivante insérée dans mon fichier maven pom.xml:

<dependency>
    <groupId>com.github.fge</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>2.0.1</version>
</dependency>

Ensuite, le code Java suivant fonctionne bien pour moi:

import Java.io.IOException;
import Java.util.Iterator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.exceptions.ProcessingException;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.jsonschema.report.ProcessingMessage;
import com.github.fge.jsonschema.report.ProcessingReport;
import com.github.fge.jsonschema.util.JsonLoader;


public class JsonValidationExample  
{

public boolean validate(String jsonData, String jsonSchema) {
    ProcessingReport report = null;
    boolean result = false;
    try {
        System.out.println("Applying schema: @<@<"+jsonSchema+">@>@ to data: #<#<"+jsonData+">#>#");
        JsonNode schemaNode = JsonLoader.fromString(jsonSchema);
        JsonNode data = JsonLoader.fromString(jsonData);         
        JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); 
        JsonSchema schema = factory.getJsonSchema(schemaNode);
        report = schema.validate(data);
    } catch (JsonParseException jpex) {
        System.out.println("Error. Something went wrong trying to parse json data: #<#<"+jsonData+
                ">#># or json schema: @<@<"+jsonSchema+">@>@. Are the double quotes included? "+jpex.getMessage());
        //jpex.printStackTrace();
    } catch (ProcessingException pex) {  
        System.out.println("Error. Something went wrong trying to process json data: #<#<"+jsonData+
                ">#># with json schema: @<@<"+jsonSchema+">@>@ "+pex.getMessage());
        //pex.printStackTrace();
    } catch (IOException e) {
        System.out.println("Error. Something went wrong trying to read json data: #<#<"+jsonData+
                ">#># or json schema: @<@<"+jsonSchema+">@>@");
        //e.printStackTrace();
    }
    if (report != null) {
        Iterator<ProcessingMessage> iter = report.iterator();
        while (iter.hasNext()) {
            ProcessingMessage pm = iter.next();
            System.out.println("Processing Message: "+pm.getMessage());
        }
        result = report.isSuccess();
    }
    System.out.println(" Result=" +result);
    return result;
}

public static void main(String[] args)
{
    System.out.println( "Starting Json Validation." );
    JsonValidationExample app = new JsonValidationExample();
    String jsonData = "\"Redemption\"";
    String jsonSchema = "{ \"type\": \"string\", \"minLength\": 2, \"maxLength\": 11}";
    app.validate(jsonData, jsonSchema);
    jsonData = "Agony";  // Quotes not included
    app.validate(jsonData, jsonSchema);
    jsonData = "42";
    app.validate(jsonData, jsonSchema);
    jsonData = "\"A\"";
    app.validate(jsonData, jsonSchema);
    jsonData = "\"The pity of Bilbo may rule the fate of many.\"";
    app.validate(jsonData, jsonSchema);
}

}

Mon résultat du code ci-dessus est:

Starting Json Validation.
Applying schema: @<@<{ "type": "string", "minLength": 2, "maxLength": 11}>@>@ to data: #<#<"Redemption">#>#
 Result=true
Applying schema: @<@<{ "type": "string", "minLength": 2, "maxLength": 11}>@>@ to data: #<#<Agony>#>#
Error. Something went wrong trying to parse json data: #<#<Agony>#># or json schema: @<@<{ "type": "string", "minLength": 2, "maxLength": 11}>@>@. Are the double quotes included?
 Result=false
Applying schema: @<@<{ "type": "string", "minLength": 2, "maxLength": 11}>@>@ to data: #<#<42>#>#
Processing Message: instance type does not match any allowed primitive type
 Result=false
Applying schema: @<@<{ "type": "string", "minLength": 2, "maxLength": 11}>@>@ to data: #<#<"A">#>#
Processing Message: string is too short
 Result=false
Applying schema: @<@<{ "type": "string", "minLength": 2, "maxLength": 11}>@>@ to data: #<#<"The pity of Bilbo may rule the fate of many.">#>#
Processing Message: string is too long
 Result=false

Prendre plaisir!

13
Tihamer

La réponse de @ Alex a fonctionné pour moi sur Android, mais m'a obligé à utiliser Multi-dex et à ajouter:

    packagingOptions {
        pickFirst 'META-INF/ASL-2.0.txt'
        pickFirst 'draftv4/schema'
        pickFirst 'draftv3/schema'
        pickFirst 'META-INF/LICENSE'
        pickFirst 'META-INF/LGPL-3.0.txt'
    }

à mon build.gradle

2
HaydenKai