I am trying to get a ChangeRequest from IBM Jazz using OSLC4J Library, but I have a problem when that ChangeRequest (in IBM called EWM workitem) contains special characters (e.g. quotation marks) in some of the fields.
When the workitem contains quotation marks in the Title or the Description (which are standard dcterms attributes) then the request works and the item is retrieved,
But,
When the special characters are in the extended/custom properties, for example “Requested Due Date Change Reason” custom text field, then it gives me the error HTTP 400 Bad Request caused by illegal instance of Datatype rdf:XMLLiteral (see the stacktrace at the end).
I checked the raw response and all text fields are of type XMLLiteral, so both the title and “Requested Due Date Change Reason” field are XML Literals, the only difference is that the title (and the description) are represented using dcterms and “Requested Due Date Change Reason” is rtc_ext.
at org.apache.jena.graph.impl.LiteralLabelImpl.getValue(LiteralLabelImpl.java:338)
at org.apache.jena.graph.Node_Literal.getLiteralValue(Node_Literal.java:44)
at org.apache.jena.rdf.model.impl.LiteralImpl.getValue(LiteralImpl.java:98)
at org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper.handleExtendedPropertyValue(JenaModelHelper.java:1154)
at org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper.fromResource(JenaModelHelper.java:659)
at org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper.createObjectResultList(JenaModelHelper.java:528)
at org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper.fromJenaModel(JenaModelHelper.java:402)
at org.eclipse.lyo.oslc4j.provider.jena.JenaModelHelper.unmarshal(JenaModelHelper.java:369)
at org.eclipse.lyo.oslc4j.provider.jena.AbstractOslcRdfXmlProvider.readFrom(AbstractOslcRdfXmlProvider.java:305)
For me it looks like that for extended/properties you have a different mechanism (JenaModelHelper.handleExtendedPropertyValue) to read properties compared to the to the procedure for reading properties from standard domains (like dcterms).
To be able to best help you, could you possibly share:
the version of OSLC4J library you are using.
the raw data you are getting back from Jazz.
Also, the exception seems to occur when OSLC4J tries to handled an “ExtendedProperty”, which are properties not defined in the ChangeRequest class you are trying to Marshall into. So, could you possibly share
The ChangeRequest class you are using in your code (or a link to the class, if you are using some existing library of classes from OSLC4J/Lyo)
I hardcoded the server name for obvious reasons, but the things that I consider important are these:
<dcterms:description rdf:datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral">this is a &quot;test&quot; description</dcterms:description>
Related to your 3rd question, I use the ChangeRequest class from OSLC4J 4.0.0 and from what I saw in the class, yes, the extended properties are not handled there but in the AbstractResource class from which ChangeRequest is extended.
I have now tried and can’t seem to easily reproduce this problem.
I tried with the following extendedProperties but they all seem to be unmarshalled fine by an OSLC Client.
Map<QName, Object> props = new HashMap<QName, Object>();
props.put(new QName("http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/", "automotive.wf.attribute.requestedduedatechangereason1"), new XMLLiteral ("test"));
props.put(new QName("http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/", "automotive.wf.attribute.requestedduedatechangereason2"), new XMLLiteral ("\"test\""));
props.put(new QName("http://jazz.net/xmlns/prod/jazz/rtc/ext/1.0/", "automotive.wf.attribute.requestedduedatechangereason3"), new XMLLiteral ("&quot;test&quot;"));
r.setExtendedProperties(props );
Do you have access to the actual values (at the user interface) for this property? If so, what is the actual value? is it "test or “"test"”
Can you also modify this value removing the quotes (and other characters like “&”) until it works?
Finally, you can also breakpoint at this point in the OSLC4J code to see exactly what the problem is.
Note though that there is some code that tries to recover from such an exception (line 1150). Only if that fails, will the exception be thrown again at line 1170.
The exception is occuring at this exact point (I believe, but you need to confirm).
The actual values in the user interface are with “ and not ;" and even if it works if it’s replaced with ;" I don’t consider it a solution because:
We cannot make sure that all the users will write it like this and it’s also not so user friendly;
There are other special characters that can cause the error, not only quotation marks (for example, ^ throws the same error).
Related to the exact point where the error occurs, you are right it’s the line that you indicated.
The error is caught at line 1150 and then it goes directly to the “else” from line 1168 and is thrown at 1170. So we checked the “if” which looks like this:
if ("false".equals(System.getProperty(AbstractOslcRdfXmlProvider.OSLC4J_STRICT_DATATYPES)))
We tried then to explicitly set this system property to false
My suggestion to modify this value is simply for debugging purposes. Of course we need to solve it for real.
So I actually don’t get the exception in my own tests. Even though I am trying to consume the same xml you shared earlier.
I am trying to guess where your problem occurs. The environment property will not help
One potential difference between our solutions is that I am running an OSLC Server that also acts as a client. Are you running a pure OSLC Client application? How does your pom.xml file look like.
Can you put a breakpoint at line 1147, and investigate the internals of literalValue ?
Yes, I am running this on an OSLC client application. The connection is made using OslcClient.java class from lyo 4.0.0.
We use Gradle instead of Maven, so these are, I think, the lyo-related dependencies that are included in build.gradle:
runtimeOnly 'org.slf4j:slf4j-simple:1.7.30'
//required for lyo version > 4.0.0
api 'org.glassfish.jersey.core:jersey-server:2.30.1'
api 'org.glassfish.jersey.containers:jersey-container-servlet:2.30.1'
api 'org.glassfish.jersey.connectors:jersey-apache-connector:2.30.1'
api 'org.glassfish.jersey.inject:jersey-hk2:2.30.1'
api ('org.eclipse.lyo:oslc-domains:4.0.0')
api('org.eclipse.lyo.clients:oslc-client:4.0.0')
So I can now reproduce the problem, which helps proceeding.
Here’s a very simple client program that illustrates the problem, with any dependencies on your tools. I read the content from a file, and try to make a ChangeRequest out of it.
run it with mvn compile exec:java -Dexec.mainClass="com.sample.client.OslcMainApplication"
What is interesting is that dcterms:description is handled fine, but not rtc_ext:reason.
This tells me that the problem is not really in Jena or the model, but certainly in our OSLC4J libraries (good to know)
I will investigate this further.
But as a workaround, consider creating a new Java class that extends ChangeRequest and adds a property to explicitly handle this reason property. I have not tested it, but if dcterms:description is working fine, it should work for the new property.
If a property has a corresponding setter (i.e. not an extended property), we fetch the value as literal (without parsing) and then check the type of the setter argument. Because the method accepts a String, we don’t even try to parse the literal as the XML literal. You get a string (but should have really gotten an exception). See JenaModelHelper.java#L779
If there is no setter, an extended property is parsed to the most concrete type we can. See JenaModelHelper.java#L1147, which is when we try to instantiate an instance of an XMLLiteral class and you get an exception (as you should).
Solution: make sure your RDF either uses a string type instead of XML literals OR make sure your XML literal is well-formed and properly escaped.
I want to suggest testing XML literal logic with Turtle instead. When you are dealing with RDF/XML, you essentially have to deal with XML serialization of RDF and then on top of that, with the validity of the XML literal encoded inside the RDF/XML. When RDF/XML is parsed (unmarshalled), property values are unescaped. And then, if your property type is XMLLiteral, they need to be valid XML after the raw value is unescaped. On the other hand, you don’t need to escape everything in XML, just things that conflict with XML.