A rest service needs to validate all incoming json data against a json schema. The json schemas are public accessible and can be retrieved via http requests.
I'm using the jackson-framwork for marshaling and unmarshaling between java and json. So far I couldn't find any possibility to validate the data against the schema by using jackson.
I also tried the JsonTools framework which obviously comes up with such a validation functionality. But unfortunately it wasn't possible for me to get the validation to work. Why JsonTool schema validation isn't working?
How can I do such a validation?
The simplest way to check if JSON is valid is to load the JSON into a JObject or JArray and then use the IsValid(JToken, JsonSchema) method with the JSON Schema. To get validation error messages, use the IsValid(JToken, JsonSchema, IList<String> ) or Validate(JToken, JsonSchema, ValidationEventHandler) overloads.
JSON Schema is a powerful tool. It enables you to validate your JSON structure and make sure it meets the required API. You can create a schema as complex and nested as you need, all you need are the requirements. You can add it to your code as an additional test or in run-time.
JSON Validator verifies that your JavaScript Object Notation adheres to the JSON specification: www.json.org. JSON Validator also formats or humanizes your JSON to render it readable following common linting practices such as multi-line and indentation.
I searched for the best practice to enforce validation for incoming json data into a RESTful service. My suggestion is to use a MessageBodyReader
which performs the validation inside the readFrom
method. Below there is an message-body-reader example which is non-generic for the sake of simplicity.
I also was interesed in finding the best framework for doing json data validation. Because I use the jackson framework (version 1.8.5) for marshaling and unmarshaling between json and java, it would have been nice if this framework would provide a json data validation functionality. Unfortunately I couldn't find any possibility to do this with jackson. Finally I got it working with the json-schema-validator available at https://github.com. The version I use is 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")); } }
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()); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With