You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jena.apache.org by "Andy Seaborne (Jira)" <ji...@apache.org> on 2020/03/02 21:55:00 UTC
[jira] [Comment Edited] (JENA-1841) Side Effect of Datatype
Use in Query
[ 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)