web-dev-qa-db-fra.com

Comment valider les données JSON entrantes dans un service REST?

Un service de repos doit valider toutes les données json entrantes par rapport à un schéma json. Les schémas json sont accessibles au public et peuvent être récupérés via des requêtes http.

J'utilise le jackson-framwork pour le marshaling et le démarshaling entre Java et json. Jusqu'à présent, je n'ai trouvé aucune possibilité de valider les données par rapport au schéma en utilisant jackson.

J'ai également essayé le framework JsonTools qui propose évidemment une telle fonctionnalité de validation. Mais malheureusement, il ne m'a pas été possible de faire fonctionner la validation. Pourquoi la validation du schéma JsonTool ne fonctionne pas?

Comment faire une telle validation?

19
My-Name-Is

J'ai recherché la meilleure pratique pour appliquer la validation des données json entrantes dans un service RESTful. Ma suggestion est d'utiliser un MessageBodyReader qui effectue la validation à l'intérieur de la méthode readFrom. Ci-dessous, il y a un exemple de lecteur de corps de message qui n'est pas générique par souci de simplicité.

J'ai également été intéressé à trouver le meilleur cadre pour faire la validation des données json. Parce que j'utilise le framework jackson (version 1.8.5) pour le marshaling et le démarshaling entre json et Java, cela aurait été bien si ce framework fournissait une fonctionnalité de validation des données json. Malheureusement, je n'ai trouvé aucune possibilité de le faire avec jackson. Enfin, je l'ai fait fonctionner avec le json-schema-validator disponible sur https: // github .com . La version que j'utilise est 2.1.7

import Java.io.BufferedReader;
import Java.io.ByteArrayInputStream;
import Java.io.FileInputStream;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.InputStreamReader;
import Java.lang.annotation.Annotation;
import Java.lang.reflect.Type;

import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.ObjectMapper;

import at.fhj.ase.dao.data.Address;
import at.fhj.ase.xmlvalidation.msbreader.MessageBodyReaderValidationException;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;
import com.github.fge.jsonschema.exceptions.ProcessingException;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.jsonschema.main.JsonValidator;
import com.github.fge.jsonschema.report.ProcessingReport;

@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class AddressJsonValidationReader implements MessageBodyReader<Address> {

    private final String jsonSchemaFileAsString;

    public AddressJsonValidationReader(@Context ServletContext servletContext) {
        this.jsonSchemaFileAsString = servletContext
                .getRealPath("/json/Address.json");
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        if (type == Address.class) {
            return true;
        }
        return false;
    }

    @Override
    public Address readFrom(Class<Address> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException, WebApplicationException {

        final String jsonData = getStringFromInputStream(entityStream);
        System.out.println(jsonData);

        InputStream isSchema = new FileInputStream(jsonSchemaFileAsString);
        String jsonSchema = getStringFromInputStream(isSchema);

        /*
         * Perform JSON data validation against schema
         */
        validateJsonData(jsonSchema, jsonData);

        /*
         * Convert stream to data entity
         */
        ObjectMapper m = new ObjectMapper();
        Address addr = m.readValue(stringToStream(jsonData), Address.class);

        return addr;
    }

    /**
     * Validate the given JSON data against the given JSON schema
     * 
     * @param jsonSchema
     *            as String
     * @param jsonData
     *            as String
     * @throws MessageBodyReaderValidationException
     *             in case of an error during validation process
     */
    private void validateJsonData(final String jsonSchema, final String jsonData)
            throws MessageBodyReaderValidationException {
        try {
            final JsonNode d = JsonLoader.fromString(jsonData);
            final JsonNode s = JsonLoader.fromString(jsonSchema);

            final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
            JsonValidator v = factory.getValidator();

            ProcessingReport report = v.validate(s, d);
            System.out.println(report);
            if (!report.toString().contains("success")) {
                throw new MessageBodyReaderValidationException(
                        report.toString());
            }

        } catch (IOException e) {
            throw new MessageBodyReaderValidationException(
                    "Failed to validate json data", e);
        } catch (ProcessingException e) {
            throw new MessageBodyReaderValidationException(
                    "Failed to validate json data", e);
        }
    }

    /**
     * Taken from <a href=
     * "http://www.mkyong.com/Java/how-to-convert-inputstream-to-string-in-Java/"
     * >www.mkyong.com</a>
     * 
     * @param is
     *            {@link InputStream}
     * @return Stream content as String
     */
    private String getStringFromInputStream(InputStream is) {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();

        String line;
        try {

            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();
    }

    private InputStream stringToStream(final String str) throws UnsupportedEncodingException {
        return new ByteArrayInputStream(str.getBytes("UTF-8"));
    }

}
17
My-Name-Is
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.jackson.JsonLoader;
import com.fasterxml.jackson.databind.JsonNode;

public class ValidationJSON {
    public static void main(String[] arr){
       String jsonData = "{\"name\": \"prem\"}";
       String jsonSchema = ""; //Schema we can generate online using http://jsonschema.net/
       final JsonNode data = JsonLoader.fromString(jsonData);
       final JsonNode schema = JsonLoader.fromString(jsonSchema);

       final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
       JsonValidator validator = factory.getValidator();

       ProcessingReport report = validator.validate(schema, data);
       System.out.println(report.isSuccess());
    }

}
9
Premraj