leadpony / justify

Justify is a JSON validator based on JSON Schema Specification and Jakarta JSON Processing API (JSON-P).
Apache License 2.0
96 stars 18 forks source link

Validation with JsonReader does not detect invalid characters after correct JsonValue #61

Closed hathiphant closed 3 years ago

hathiphant commented 3 years ago

When using a JsonReader with a schema, the first value is read (and validated), but if there is some other characters after the valid JSON data, this is not detected as invalid (no exception or validation message that EOF is not attained). This can be solved with a JsonReader using internally a JsonParser with a loop while (parser.hasNext()) to match fully the stream.

import java.io.StringReader;
import java.util.stream.Collectors;

import org.leadpony.justify.api.InstanceType;
import org.leadpony.justify.api.JsonSchema;
import org.leadpony.justify.api.JsonValidationService;
import org.leadpony.justify.api.Problem;
import org.leadpony.justify.api.ProblemHandler;

import jakarta.json.JsonReader;
import jakarta.json.spi.JsonProvider;
import jakarta.json.stream.JsonParser;

public class TestSchema
{

    public static void main(String[] args) {
        JsonValidationService validator = JsonValidationService.newInstance();
        JsonSchema schema = validator.createSchemaBuilderFactory().createBuilder()
            .withType(InstanceType.INTEGER).build();
        ProblemHandler handler = problems -> System.err
            .println(problems.stream().map(Problem::toString).collect(Collectors.joining("\n")));
        JsonProvider provider = validator.createJsonProvider(schema, parser -> handler);
        // Bugged JSON with data after (first) value
        String buggedJSON = "2 3";
        {
            try (JsonReader reader = provider.createReader(new StringReader(buggedJSON))) {
                System.out.println("Reader: " + reader.readValue().toString());
            }
            // Does not throw any exception even if data are globally invalid (because more
            // data are available after first value and before EOF)
        }
        {
            try (JsonParser parser = provider.createParser(new StringReader(buggedJSON))) {
                parser.next();
                do {
                    System.out.println("Parser: " + parser.getValue().toString());
                } while (parser.hasNext());
            }
            // Throws correctly an exception:
            // jakarta.json.stream.JsonParsingException: Expected EOF token, but got NUMBER
        }
        // A solution would be to make a custom implementation of JsonReader using
        // internally a JsonParser, to loop while parser.hasNext() and attaining really
        // the EOF.
    }

}
leadpony commented 3 years ago

@hathiphant

This is correct behavior provided by Jakarta JSON Processing API. Try the following code which uses Jakarta JSON Processing API directly without Justify.

String json = "2 3";
try (JsonReader reader = Json.createReader(new StringReader(json))) {
    System.out.println(reader.readValue());
}
// result: 2 is printed 

If you think this behavior is not good, please contact JSON-P project.

hathiphant commented 3 years ago

Thank you for your response and sorry to bother you. I reported the problem to your very good validator, because I was more surprised with a validating parser not detecting invalid data than a non-validating parser.

After searching in bugs of JSON-P, I have found eclipse-ee4j/jsonp#171 which seems to be the same problem, and does not seems to evolve. If I have too many uses of JsonReader, I will make my own JsonReader wrapping a JsonParser to detect this type of problems.

I perfectly understand if you close this issue, because the problem in data relates to JSON syntax and not JSON schema.

Thank you very much.