Repository: jena Updated Branches: refs/heads/master 123cf4cb3 -> 6a0fee3ca
JENA-1013 : Generate triples then parse error. Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/93d2d532 Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/93d2d532 Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/93d2d532 Branch: refs/heads/master Commit: 93d2d532da88e356e381b1555f95f64ded6a6065 Parents: 123cf4c Author: Andy Seaborne <[email protected]> Authored: Sun Aug 23 21:14:06 2015 +0100 Committer: Andy Seaborne <[email protected]> Committed: Sun Aug 23 21:14:06 2015 +0100 ---------------------------------------------------------------------- .../org/apache/jena/riot/lang/JsonLDReader.java | 108 ++++++++++++++++--- 1 file changed, 95 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/93d2d532/jena-arq/src/main/java/org/apache/jena/riot/lang/JsonLDReader.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/lang/JsonLDReader.java b/jena-arq/src/main/java/org/apache/jena/riot/lang/JsonLDReader.java index 4c85264..09073c6 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/lang/JsonLDReader.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/lang/JsonLDReader.java @@ -25,6 +25,7 @@ import java.util.List ; import java.util.Map ; import java.util.Objects; import java.util.Map.Entry; +import java.util.function.Consumer ; import org.apache.jena.atlas.io.IO ; import org.apache.jena.atlas.lib.InternalErrorException ; @@ -40,9 +41,11 @@ import org.apache.jena.riot.RiotException ; import org.apache.jena.riot.system.* ; import org.apache.jena.sparql.core.Quad ; import org.apache.jena.sparql.util.Context ; +import org.apache.jena.util.FileUtils ; +import com.fasterxml.jackson.core.* ; +import com.fasterxml.jackson.databind.ObjectMapper ; import com.github.jsonldjava.core.* ; -import com.github.jsonldjava.utils.JsonUtils ; public class JsonLDReader implements ReaderRIOT { @@ -55,33 +58,113 @@ public class JsonLDReader implements ReaderRIOT @Override public ParserProfile getParserProfile() { return parserProfile ; } @Override public void setParserProfile(ParserProfile parserProfile) { this.parserProfile = parserProfile ; } + // pre jsonld-java issue #144 code. + // Remove at any point. +// @Override +// public void read(Reader reader, String baseURI, ContentType ct, StreamRDF output, Context context) { +// try { +// Object jsonObject = JsonUtils.fromReader(reader) ; +// read$(jsonObject, baseURI, ct, output, context) ; +// } +// catch (IOException e) { +// IO.exception(e) ; +// } +// } +// +// @Override +// public void read(InputStream in, String baseURI, ContentType ct, StreamRDF output, Context context) { +// try { +// Object jsonObject = JsonUtils.fromInputStream(in) ; +// read$(jsonObject, baseURI, ct, output, context) ; +// } +// catch (IOException e) { +// IO.exception(e) ; +// } +// } + + // This addresses jsonld-java issue #144 so that we get triples/quads out + // then there is a parse error. Even if it is fixed in jsonld-java, it would + // mean that no triples would be produced - all the JSON parsing is done + // before JSON-LD processing. Here we process the first JSON object, whch + // causes triples to be generated then decide whether to throw a parse + // error. This is more in the style of other syntaxes and stream parsing. + @Override public void read(Reader reader, String baseURI, ContentType ct, StreamRDF output, Context context) { - if ( parserProfile == null ) - parserProfile = RiotLib.profile(RDFLanguages.JSONLD, baseURI, errorHandler) ; try { - Object jsonObject = JsonUtils.fromReader(reader) ; - read$(jsonObject, baseURI, ct, output, context) ; + readProcess(reader, + (jsonObject)->read$(jsonObject, baseURI, ct, output, context)) ; + } + catch (JsonProcessingException ex) { + // includes JsonParseException + // The Jackson JSON parser, or addition JSON-level check, throws up something. + JsonLocation loc = ex.getLocation() ; + errorHandler.error(ex.getOriginalMessage(), loc.getLineNr(), loc.getColumnNr()); + throw new RiotException(ex.getOriginalMessage()) ; } catch (IOException e) { + errorHandler.error(e.getMessage(), -1, -1); IO.exception(e) ; } } @Override public void read(InputStream in, String baseURI, ContentType ct, StreamRDF output, Context context) { - if ( parserProfile == null ) - parserProfile = RiotLib.profile(RDFLanguages.JSONLD, baseURI, errorHandler) ; - try { - Object jsonObject = JsonUtils.fromInputStream(in) ; - read$(jsonObject, baseURI, ct, output, context) ; + Reader r = FileUtils.asBufferedUTF8(in) ; + read(r, baseURI, ct, output, context) ; + } + + // From JsonUtils.fromReader in the jsonld-java codebase. + // Note that jsonld-java always uses a reader. + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + private static final JsonFactory JSON_FACTORY = new JsonFactory(JSON_MAPPER); + + /** Read a JSON object from the reader, acall the prcoessing function, then + * check for trailing content. For Jena, this means tripes/quads are generated + * from a valid JSON object, then there is a parse error for trailing junk. + * @param reader + * @param function + * @throws IOException + */ + private static void readProcess(Reader reader, Consumer<Object> function) throws IOException { + final JsonParser jp = JSON_FACTORY.createParser(reader); + Object rval ; + final JsonToken initialToken = jp.nextToken(); + + if (initialToken == JsonToken.START_ARRAY) { + rval = jp.readValueAs(List.class); + } else if (initialToken == JsonToken.START_OBJECT) { + rval = jp.readValueAs(Map.class); + } else if (initialToken == JsonToken.VALUE_STRING) { + rval = jp.readValueAs(String.class); + } else if (initialToken == JsonToken.VALUE_FALSE || initialToken == JsonToken.VALUE_TRUE) { + rval = jp.readValueAs(Boolean.class); + } else if (initialToken == JsonToken.VALUE_NUMBER_FLOAT + || initialToken == JsonToken.VALUE_NUMBER_INT) { + rval = jp.readValueAs(Number.class); + } else if (initialToken == JsonToken.VALUE_NULL) { + rval = null; + } else { + throw new JsonParseException("document doesn't start with a valid json element : " + + initialToken, jp.getCurrentLocation()); } - catch (IOException e) { - IO.exception(e) ; + + function.accept(rval); + + JsonToken t ; + try { t = jp.nextToken(); } + catch (JsonParseException ex) { + throw new JsonParseException("Document contains more content after json-ld element - (possible mismatched {}?)", + jp.getCurrentLocation()); } + if ( t != null ) + throw new JsonParseException("Document contains possible json content after the json-ld element - (possible mismatched {}?)", + jp.getCurrentLocation()); } private void read$(Object jsonObject, String baseURI, ContentType ct, final StreamRDF output, Context context) { + if ( parserProfile == null ) + parserProfile = RiotLib.profile(RDFLanguages.JSONLD, baseURI, errorHandler) ; output.start() ; try { JsonLdTripleCallback callback = new JsonLdTripleCallback() { @@ -186,5 +269,4 @@ public class JsonLDReader implements ReaderRIOT RDFDatatype dt = NodeFactory.getType(datatype) ; return NodeFactory.createLiteral(lex, dt) ; } - }
