This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push: new e68c9dd07d GH-2555: Allow ^^rdf:langString in result sets e68c9dd07d is described below commit e68c9dd07d64a2b98edd0e5bd8e1b20326611905 Author: Andy Seaborne <a...@apache.org> AuthorDate: Fri Jul 5 18:50:27 2024 +0100 GH-2555: Allow ^^rdf:langString in result sets --- jena-arq/pom.xml | 5 + .../org/apache/jena/riot/rowset/RowSetReader.java | 7 +- .../jena/riot/rowset/RowSetReaderRegistry.java | 9 ++ .../jena/riot/resultset/TS_ResultSetRIOT.java | 10 +- .../org/apache/jena/riot/rowset/TS_RowSetRIOT.java | 12 ++- .../jena/riot/rowset/rw/TestRowSetReader.java | 120 +++++++++++++++++++++ .../java/org/apache/jena/graph/NodeFactory.java | 30 ++++-- .../apache/jena/graph/test/TestNodeEdgeCases.java | 47 ++++++++ .../apache/jena/graph/test/TestPackage_graph.java | 1 + 9 files changed, 224 insertions(+), 17 deletions(-) diff --git a/jena-arq/pom.xml b/jena-arq/pom.xml index 0efa9cd1c8..952b52a4ae 100644 --- a/jena-arq/pom.xml +++ b/jena-arq/pom.xml @@ -127,6 +127,11 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-suite-engine</artifactId> + </dependency> + <dependency> <groupId>org.awaitility</groupId> <artifactId>awaitility</artifactId> diff --git a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java index 264f9cf9f6..c45b525488 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java @@ -21,12 +21,12 @@ package org.apache.jena.riot.rowset; import java.io.InputStream; import java.io.Reader; +import org.apache.jena.riot.Lang; import org.apache.jena.sparql.exec.QueryExecResult; import org.apache.jena.sparql.exec.RowSet; import org.apache.jena.sparql.util.Context; public interface RowSetReader { - /** * Read from an {@code InputStream} and produce a {@link RowSet}. * Note that return row set may stream and so the input stream may be read @@ -67,4 +67,9 @@ public interface RowSetReader { public default RowSet read(Reader in, Context context) { throw new UnsupportedOperationException("RowSetReader.read - input from a Java Reader not supported. Use an InputStream."); } + + /** Convenience operation - create a {@link RowSetReader} for {@link Lang} or return null. */ + public static RowSetReader createReader(Lang lang) { + return RowSetReaderRegistry.createReader(lang); + } } diff --git a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java index 582fe3ba31..20da936741 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java @@ -35,6 +35,15 @@ public class RowSetReaderRegistry { return registry.get(lang); } + /** Create a {@link RowSetReader} for {@link Lang} or return null. */ + public static RowSetReader createReader(Lang lang) { + Objects.requireNonNull(lang); + RowSetReaderFactory factory = getFactory(lang); + if ( factory == null ) + return null; + return factory.create(lang); + } + /** Register a {@link RowSetReaderFactory} for a {@link Lang} */ public static void register(Lang lang, RowSetReaderFactory factory) { Objects.requireNonNull(lang); diff --git a/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java b/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java index f29ee4b0d8..8b214fedf5 100644 --- a/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java +++ b/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java @@ -20,15 +20,15 @@ package org.apache.jena.riot.resultset; import org.apache.jena.riot.resultset.rw.TestResultSetWriterCSV; import org.apache.jena.riot.resultset.rw.TestResultSetWriterTSV; -import org.junit.runner.RunWith ; -import org.junit.runners.Suite ; +import org.junit.platform.suite.api.*; -@RunWith(Suite.class) -@Suite.SuiteClasses( { +@Suite +@SelectClasses({ TestResultSetIO.class + , TestResultSetLang.class , TestResultSetWriterCSV.class , TestResultSetWriterTSV.class , TestResultSetLang.class -}) + }) public class TS_ResultSetRIOT { } diff --git a/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java b/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java index 2cd1f05b4b..d2d91e562d 100644 --- a/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java +++ b/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java @@ -18,15 +18,17 @@ package org.apache.jena.riot.rowset; +import org.apache.jena.riot.rowset.rw.TestRowSetReader; import org.apache.jena.riot.rowset.rw.TestRowSetWriterCSV; import org.apache.jena.riot.rowset.rw.TestRowSetWriterTSV; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite;; -@RunWith(Suite.class) -@Suite.SuiteClasses( { +@Suite +@SelectClasses({ TestRowSetWriterCSV.class, - TestRowSetWriterTSV.class + TestRowSetWriterTSV.class, + TestRowSetReader.class }) public class TS_RowSetRIOT { } diff --git a/jena-arq/src/test/java/org/apache/jena/riot/rowset/rw/TestRowSetReader.java b/jena-arq/src/test/java/org/apache/jena/riot/rowset/rw/TestRowSetReader.java new file mode 100644 index 0000000000..c340a19023 --- /dev/null +++ b/jena-arq/src/test/java/org/apache/jena/riot/rowset/rw/TestRowSetReader.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.riot.rowset.rw; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.jena.atlas.io.IOX; +import org.apache.jena.atlas.lib.Bytes; +import org.apache.jena.query.ARQ; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.resultset.ResultSetLang; +import org.apache.jena.riot.rowset.RowSetReader; +import org.apache.jena.sparql.exec.RowSet; +import org.apache.jena.sparql.exec.RowSetOps; +import org.apache.jena.sys.JenaSystem; +import org.junit.jupiter.api.Test; + +/** + * Addition tests for result readers. + * The SPARQl test suite cover most usage. This class adds tests + */ +public class TestRowSetReader { + static { JenaSystem.init(); } + + // Check "abc"^^rdf:langString and "abc"^^rdf:dirLangString and " + @Test public void resultSet_json_1() { + String r = """ + { + "head": { "vars": [ "s" , "p" , "o" ] } , + "results": { + "bindings": [ + { + "s": { "type": "uri" , "value": "http://example/s" } , + "p": { "type": "uri" , "value": "http://example/p" } , + "o": { "type": "literal" , "datatype": "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString" , "value": "abc" } + } , + { + "s": { "type": "uri" , "value": "http://example/s" } , + "p": { "type": "uri" , "value": "http://example/p" } , + "o": { "type": "literal" , "datatype": "http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString" , "value": "abc" } + } + ] + }} + """; + RowSet rowset = read(r, ResultSetLang.RS_JSON); + assertNotNull(rowset); + assertEquals(2, RowSetOps.count(rowset)); + } + + @Test public void resultSet_xml_1() { + String r = """ +<?xml version="1.0"?> +<sparql xmlns="http://www.w3.org/2005/sparql-results#"> + <head> + <variable name="s"/> + <variable name="p"/> + <variable name="o"/> + </head> + <results> + <result> + <binding name="s"> + <uri>http://example/s</uri> + </binding> + <binding name="p"> + <uri>http://example/p</uri> + </binding> + <binding name="o"> + <literal datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#langString">abc</literal> + </binding> + </result> + <result> + <binding name="s"> + <uri>http://example/s</uri> + </binding> + <binding name="p"> + <uri>http://example/p</uri> + </binding> + <binding name="o"> + <literal datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString">abc</literal> + </binding> + </result> + + </results> +</sparql> + """; + RowSet rowset = read(r, ResultSetLang.RS_XML); + assertNotNull(rowset); + assertEquals(2, RowSetOps.count(rowset)); + } + + private static RowSet read(String x, Lang rsLang) { + try ( InputStream input = new ByteArrayInputStream(Bytes.string2bytes(x)) ) { + RowSet rowSet = RowSetReader.createReader(rsLang) + .read(input, ARQ.getContext().copy()) + .materialize(); + return rowSet; + } catch (IOException ex) { throw IOX.exception(ex); } + } +} diff --git a/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java b/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java index 264046092f..4979cb06c8 100644 --- a/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java +++ b/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java @@ -224,22 +224,40 @@ public class NodeFactory { if ( ! dtype.equals(RDFLangString.rdfLangString) ) throw new JenaException("Datatype is not rdf:langString but a language was given"); } else { - if ( ! dtype.equals(RDFDirLangString.rdfDirLangString) ) + if ( ! dtype.equals(RDFDirLangString.rdfDirLangString) ) throw new JenaException("Datatype is not rdf:dirLangString but a language and initial text direction was given"); } } return createLiteralDirLang(lex, langFmt, textDir); } + if ( dtype == null ) // No datatype, no lang (it is null or "") => xsd:string. return createLiteralString(lex); - // No lang, with a datatype - if ( dtype.equals(RDFLangString.rdfLangString) ) - throw new JenaException("Datatype is rdf:langString but no language given"); - if ( dtype.equals(RDFDirLangString.rdfDirLangString) && noTextDir(textDir) ) - throw new JenaException("Datatype is rdf:dirLangString but no initial text direction given"); + // No language. Has a datatype. + boolean hasTextDirLang = ( textDir != null ); + if ( hasTextDirLang ) { + if ( dtype.equals(RDFDirLangString.rdfDirLangString) ) { + // No language. Datatype is rdf:dirLangString, Does have an initial text direction + throw new JenaException("Datatype is rdf:dirLangString and has an initial text direction but no language given"); + } else if ( dtype.equals(RDFLangString.rdfLangString) ) { + // No language. Datatype is rdf:langString, Does have an initial text direction. + throw new JenaException("Datatype is rdf:langString and has an initial text direction but no language given"); + } + } + + // Datatype. No language, no initial text direction. + // Allow "abc"^^rdf:langString + // Allow "abc"^^rdf:dirLangString + + // To disallow. +// if ( dtype.equals(RDFLangString.rdfLangString) ) +// throw new JenaException("Datatype is rdf:langString but no language given"); +// if ( dtype.equals(RDFDirLangString.rdfDirLangString) && noTextDir(textDir) ) +// throw new JenaException("Datatype is rdf:dirLangString but no initial text direction given"); + Node n = createLiteralDT(lex, dtype); return n; } diff --git a/jena-core/src/test/java/org/apache/jena/graph/test/TestNodeEdgeCases.java b/jena-core/src/test/java/org/apache/jena/graph/test/TestNodeEdgeCases.java new file mode 100644 index 0000000000..43cd6f2813 --- /dev/null +++ b/jena-core/src/test/java/org/apache/jena/graph/test/TestNodeEdgeCases.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.graph.test; + +import static org.junit.Assert.assertNotNull; + +import org.apache.jena.datatypes.xsd.impl.RDFDirLangString; +import org.apache.jena.datatypes.xsd.impl.RDFLangString; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.junit.Test; + +public class TestNodeEdgeCases { + + // Corner cases of NodeFactory + @Test public void term_create_01() { + // "abc"^^rdf:langString (no language) + Node node1 = NodeFactory.createLiteral("abc", null, (String)null, RDFLangString.rdfLangString); + assertNotNull(node1); + Node node2 = NodeFactory.createLiteralDT("abc", RDFLangString.rdfLangString); + assertNotNull(node2); + } + + @Test public void term_create_02() { + // "abc"^rdf:dirLangString (no language, no initial text direction) + Node node1 = NodeFactory.createLiteral("abc", null, (String)null, RDFDirLangString.rdfDirLangString); + assertNotNull(node1); + Node node2 = NodeFactory.createLiteralDT("abc", RDFDirLangString.rdfDirLangString); + assertNotNull(node2); + } +} diff --git a/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java b/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java index 5236ca13b5..ee2606b951 100644 --- a/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java +++ b/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java @@ -55,6 +55,7 @@ public class TestPackage_graph extends TestSuite { addTestSuite( TestGraphBaseToString.class ); addTest( new JUnit4TestAdapter(TestNodeExtras.class) ); addTest( new JUnit4TestAdapter(TestRDFStringLiterals.class) ); + addTest( new JUnit4TestAdapter(TestNodeEdgeCases.class) ); // Has to be in a different package. addTest( new JUnit4TestAdapter(TestGraphUtil.class) );