[ https://issues.apache.org/jira/browse/JENA-1841?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17049514#comment-17049514 ]
Andy Seaborne edited comment on JENA-1841 at 3/2/20 9:54 PM: ------------------------------------------------------------- This is enough to trigger the issue: with either "if" block active: {code:java} public static void main(String ... a) { UUID uuid = UUID.fromString("00000000-0000-0000-0000-000000000007"); if ( true ) { LiteralLabel ll = LiteralLabelFactory.createTypedLiteral(uuid); } if ( false ) { SelectBuilder select = new SelectBuilder(); select.getExprFactory().eq("?uuid", uuid); } // The bad lexical form is not relevant. Just shortened for JIRA. String modelStr = "_:a <http://example.org/p1> '00000000'^^<java:java.util.UUID> ."; Model model = ModelFactory.createDefaultModel().read(new StringReader(modelStr), "", "N-TRIPLE"); System.out.println("DONE"); } {code} {{select.getExprFactory().eq("?uuid", uuid);}} calls {{LiteralLabelFactory.createTypedLiteral(uuid)}}. {{LiteralLabelFactory.createTypedLiteral(uuid)}} tries to register a datatype for java class UUID - no URI given. The problem is that there is no full registration for Java Object to datatype with URI, only a placeholder ({{AdHocDatatype}}. When the parser runs or any way a literal node if created from a string, Jena attempts to find the value but there is no code for UUID string to UUID. What can {{SelectBuilder}} do about unknown datatypes? (Ping [~claude]). It does not get the {{<java:java.util.UUID>}}, only the java object, so proper registration can't happen. Maybe it should not support unregistered types and signal that with a clear exception. Normally when parsing (RIOT or SPARQL) unknowns, {{TypeMapper.getSafeTypeByName}} happens which creates a {{BaseDatatype}} but in this case, the datatype URI is known and is the placeholder. To register a datatype: do this before using {{SelectBuilder}}: (only weakly tested): {code:java} RDFDatatype dtx = new BaseDatatype("java:java.util.UUID") { @Override public Class<?> getJavaClass() { return UUID.class; } @Override public Object parse(String lexicalForm) throws DatatypeFormatException { try { return UUID.fromString(lexicalForm); } catch (Throwable th) { throw new DatatypeFormatException(); } } }; TypeMapper.getInstance().registerDatatype(dtx); {code} Finally - did the code mean to use a URI: {{<urn:uuid:00000000-0000-0000-0000-000000000007>}}? was (Author: andy.seaborne): This is enough to trigger the issue: with either "if" block active: {code:java} public static void main(String ... a) { UUID uuid = UUID.fromString("00000000-0000-0000-0000-000000000007"); if ( true ) { LiteralLabel ll = LiteralLabelFactory.createTypedLiteral(uuid); } if ( false ) { SelectBuilder select = new SelectBuilder(); select.getExprFactory().eq("?uuid", uuid); } // The bad lexical form is not relevant. Just shortened for JIRA. String modelStr = "_:a <http://example.org/p1> '00000000'^^<java:java.util.UUID> ."; Model model = ModelFactory.createDefaultModel().read(new StringReader(modelStr), "", "N-TRIPLE"); System.out.println("DONE"); } {code} {{select.getExprFactory().eq("?uuid", uuid);}} calls {{LiteralLabelFactory.createTypedLiteral(uuid)}}. {{LiteralLabelFactory.createTypedLiteral(uuid)}} tries to register a datatype for java class UUID - no URI given. The problem is that there is no full registration for Java Object to datatype with URI, only a placeholder ({{AdHocDatatype}}. When the parser runs or any way a literal node if created from a string, Jena attempts to find the value but there is no code for UUID string to UUID. What can {{SelectBuilder}} do about unknown datatypes? (Ping [~claude]). It does not get the {{<java:java.util.UUID>}}, only the java object, so proper registration can't happen. Maybe it should not support unregistered types and signal that with a clear exception. Normally when parsing (RIOT or SPARQL) unknowns, {{TypeMapper.getSafeTypeByName}} happens which creates a {{BaseDatatype}} but in this case, the datatype URI is known and is the placeholder. To register a datatype: do this before using {{SelectBuilder}}: (only weakly tested): {code:java} RDFDatatype dtx = new BaseDatatype("java:java.util.UUID") { @Override public Class<?> getJavaClass() { return UUID.class; } @Override public Object parse(String lexicalForm) throws DatatypeFormatException { try { UUID.fromString(lexicalForm); return lexicalForm; } catch (Throwable th) { throw new DatatypeFormatException(); } } }; TypeMapper.getInstance().registerDatatype(dtx); {code} Finally - did the code mean to use a URI: {{<urn:uuid:00000000-0000-0000-0000-000000000007>}}? > Side Effect of Datatype <java:java.util.UUID> Use in Query > ---------------------------------------------------------- > > Key: JENA-1841 > URL: https://issues.apache.org/jira/browse/JENA-1841 > Project: Apache Jena > Issue Type: Bug > Affects Versions: Jena 3.14.0 > Reporter: Jan Martin Keil > Priority: Major > > I faced a bug caused by a side effect of using the datatype > <java:java.util.UUID> in a query. > Short story is that you can not use this datatype in model parsing or queries > after you once used it in a query. > I did not completely break it down to a specific peace of code, but I wrote > some testcases that narrow down the issue. Please note that the order of > execution of the test methods effect the result. So please first try to > execute single test methods before executing the whole test class. > {code:java} > import java.io.ByteArrayInputStream; > import java.util.UUID; > import org.apache.jena.arq.querybuilder.SelectBuilder; > import org.apache.jena.query.QueryExecution; > import org.apache.jena.query.QueryExecutionFactory; > import org.apache.jena.rdf.model.Model; > import org.apache.jena.rdf.model.ModelFactory; > import org.junit.jupiter.api.Test; > public class UuidParsingintoModelOrQuery { > @Test > public void uuidParsingIntoSingleModel() throws Exception { > UUID uuid1 = > UUID.fromString("00000000-0000-0000-0000-000000000000"); > UUID uuid2 = > UUID.fromString("00000000-0000-0000-0000-000000000001"); > String modelStr = "_:a <http://example.org/p1> \"" + uuid1 + > "\"^^<java:java.util.UUID> .\n" > + "_:a <http://example.org/p2> \"" + uuid1 + > "\"^^<java:java.util.UUID> ."; > ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", "N-TRIPLE"); > // repeat > modelStr = "_:a <http://example.org/p1> \"" + uuid2 + > "\"^^<java:java.util.UUID> .\n" > + "_:a <http://example.org/p2> \"" + uuid2 + > "\"^^<java:java.util.UUID> ."; > ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", "N-TRIPLE"); > } > @Test > public void sameUuidParsingIntoSingleModel() throws Exception { > UUID uuid1 = > UUID.fromString("00000000-0000-0000-0000-000000000002"); > UUID uuid2 = > UUID.fromString("00000000-0000-0000-0000-000000000003"); > String modelStr = "_:a <http://example.org/p1> \"" + uuid1 + > "\"^^<java:java.util.UUID> .\n" > + "_:a <http://example.org/p2> \"" + uuid2 + > "\"^^<java:java.util.UUID> ."; > ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", "N-TRIPLE"); > // repeat > ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", "N-TRIPLE"); > } > @Test > public void sameUuidParsingIntoMultipleModel() throws Exception { > UUID uuid = > UUID.fromString("00000000-0000-0000-0000-000000000004"); > String modelStr = "_:a <http://example.org/p1> \"" + uuid + > "\"^^<java:java.util.UUID> ."; > ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", "N-TRIPLE"); > ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", "N-TRIPLE"); > } > @Test > public void uuidUseInQuery() throws Exception { > UUID uuid = > UUID.fromString("00000000-0000-0000-0000-000000000005"); > SelectBuilder select = new SelectBuilder(); > select.addWhere("?a", "<http://example.org/p>", "?uuid"); > select.addFilter(select.getExprFactory().eq("?uuid", uuid)); > QueryExecution q = QueryExecutionFactory.create(select.build()); > } > @Test > public void uuidParsingIntoQuery() throws Exception { > UUID uuid = > UUID.fromString("00000000-0000-0000-0000-000000000006"); > SelectBuilder select = new SelectBuilder(); > select.addWhere("?a", "<http://example.org/p>", "?uuid"); > select.addFilter(select.getExprFactory().eq("?uuid", uuid)); > QueryExecution q = > QueryExecutionFactory.create(select.toString()); > } > @Test > public void uuidUseInQueryAndParsingIntoModel() throws Exception { > UUID uuid = > UUID.fromString("00000000-0000-0000-0000-000000000007"); > SelectBuilder select = new SelectBuilder(); > select.addWhere("?a", "<http://example.org/p>", "?uuid"); > select.addFilter(select.getExprFactory().eq("?uuid", uuid)); > QueryExecution q = QueryExecutionFactory.create(select.build()); > String modelStr = "_:a <http://example.org/p1> \"" + uuid + > "\"^^<java:java.util.UUID> .\n" > + "_:a <http://example.org/p2> \"" + uuid + > "\"^^<java:java.util.UUID> ."; > Model model = ModelFactory.createDefaultModel().read(new > ByteArrayInputStream(modelStr.getBytes()), "", > "N-TRIPLE"); > } > } > {code} -- This message was sent by Atlassian Jira (v8.3.4#803005)