kbss-cvut / jb4jsonld Goto Github PK
View Code? Open in Web Editor NEWJSON-LD serialization and deserialization for Java REST services.
License: GNU Lesser General Public License v3.0
JSON-LD serialization and deserialization for Java REST services.
License: GNU Lesser General Public License v3.0
As a follow up to #9, handling of date, time and datetime objects should be solved in general.
First, support for Java 8 Date/Time API should be added.
Second, serialization of these (and java.util.Date
) should perhaps be configurable (time in milliseconds vs. formatted string).
Third, deserialization should be working accordingly as well.
Both the maven builds for this project and downstream projects fail as a result of failing tests without SCAN_PACKAGE set when running using JDK11.
jsonld2java transformation generates exception if input jsonld document has a blank node. The exception is due to failed attempt to transform blank node to an URI (i assume it from the stack trace that i saw). Although i did not try it on this data, in text below i created 2 examples of semantically same jsonld document. First one should succeed in transformation while second one i believe would not ...
First, jsonld document that i think would work:
{
"http://example.org/property" : "value",
"http://example.org/property2" : {
"http://example.org/inner-property" : "otherValue"
}
}
If i transform previous jsonld document using jsonld transformation "flattened", i will get equivalent jsonld document which i believe would fail within jsonld2java transformation:
{
"@graph": [
{
"@id": "_:b0",
"http://example.org/property": "value",
"http://example.org/property2": {
"@id": "_:b1"
}
},
{
"@id": "_:b1",
"http://example.org/inner-property": "otherValue"
}
]
}
Workaround in this case would be removing all "@id" properties, since all of the objects are referenced only once. This is however not general case..
Link to the example in jsonld playground.
Currently, MultilingualString
values without language (represented by a null
language tag value) are serialized as
{
"null": "Language-less value"
}
This is not correct w.r.t. the JSON-LD 1.1 specification and while jsonld-java, which we are using for processing JSON-LD, works under JSON-LD 1.0, this causes issues with integration with client-side libraries like jsonld.js.
The aforementioned input should be serialized as:
{
"@none": "Language-less value"
}
I have a class C with a single-valued property p and a range constraint which restrict the range of p to a class D (this constraint is espressed as a subclass constraint assertion on C). D has two subclasses D' and D''. In my json file I has a property assertion
stating that an individual of class C is linked to an individual which belongs to both classes D' and D'' (D'' is the same) via the property p. I would expect that the individual of class D' would be deserialized as individual of (the java class corresponding to) D, in light of the constraint on C. However an AmbiguousTargetTypeException is thrown as D' and D'' are detected as possible target candidates. See cz.cvut.kbss.jsonld.deserialization.util.TargetClassResolver, row 48.
Please let me know if a pull request to fix it as I would expect may be appropriate.
JSON-LD allows using references to objects via their id. The problem is, when the input is being processed, the order of attributes might change and thus the id reference could be deserialized before the full object.
A solution to this problem could be to defer resolution of such references until the full object has been encountered.
When an entity has a types field, the serialization creates duplicate @type
property, one for the @OWLClass
value and the other for the value of @Types
attribute.
These should be unified.
As a user, I want to be able to override property mapping. The main use case after implementing #16 would be preventing term mapping conflicts in context, e.g., when two classes have a field with the same name but different mapped property, it is not possible to serialize them at the same time because a term mapping conflict would occur in the context. Property overriding would solve this.
Note that this has to work both for serialization and deserialization.
It would be great to be able to translate jsonld language map fields defined with Language Indexing.
I'm not sure what the best way to handle this would be with regards to the Java mappings though.
I created a Class annotated with the OWLClass annotation. This class has a field properties
annotated with the @Properties
JOPA annotation. Following javadoc, my properties field has tipe Map<String, Set<Object>>
. Infact, I need to specify an object unmapped property here. Thus, for analogy with @OWLObjectProperty
, I put in this map a singleton with an object of type URI
. I would expect that, when serializing, this URI is used to construct the property target as an individual with this URI as @Id
. However, instead the property is interpreted as a datatype property and the URI as a string literal.
I tried also with using an object of another class annotated as @OWLClass
instead of a URI
. In this case the string literal produced in serialization is the class name. I suppose that in both cases just the toString
method of the object is used to generate the literal.
With debugging, I saw that fields annotated with @Property
annotation are processed by the cmethod cz.cvut.kbss.jsonld.serialization.PropertyFieldSerializer.serializePropertyValues
which I assume works only for literals.
When using JB4JSON-LD in a Spring Boot-based application, there is problem with classpath scanning. It expects multi-release info in META-INF
while it can be in BOOT-INF
for Spring Boot applications.
If java object model contains more than one reference to the same java object it is serialized into json-ld incorrectly:
{
"http://onto.fel.cvut.cz/ontologies/documentation/has_related_question" : {
"@id": "http://onto.fel.cvut.cz/1-q",
"@type": "http://onto.fel.cvut.cz/ontologies/documentation/question"
}
}
{
"http://onto.fel.cvut.cz/ontologies/documentation/has_related_question" : "http://onto.fel.cvut.cz/1-q"
}
From such document it is inferred by a json-ld processor, that subsequent references refers to string "http://onto.fel.cvut.cz/1-q", not IRI http://onto.fel.cvut.cz/1-q.
To fix this issue there are 2 possible solutions:
{
"@context": {
"http://onto.fel.cvut.cz/ontologies/documentation/has_related_question" : {
"@id" : "http://onto.fel.cvut.cz/ontologies/documentation/has_related_question",
"@type" : "@id"
}
},
"@graph": [
{
.....
{
"http://onto.fel.cvut.cz/ontologies/documentation/has_related_question": [
{
"@id": "http://onto.fel.cvut.cz/871-q"
}
....
Currently in ActivityStreams4J, when a target type parameter is missing from the jsonld, an exception ocurs:
{
"@context" : "https://www.w3.org/ns/activitystreams",
"name" : "Foo",
"id" : "http://example.org/foo"
}
cz.cvut.kbss.jsonld.exception.TargetTypeException: Neither class social.pantheon.activitystreams4j.core.ObjectDTO nor any of its subclasses matches the types [].
at cz.cvut.kbss.jsonld.deserialization.util.TargetClassResolver.getTargetClass(TargetClassResolver.java:53)
at cz.cvut.kbss.jsonld.deserialization.expanded.Deserializer.resolveTargetClass(Deserializer.java:45)
It would be great if there was a way to specify that JB4JSONLD was allowed to assume the type of the object to be the base class it was told to serialize if no type parameter was provided.
Le C
be an OWL class which defines an single value cardinality constraint (cardinality==1) on some property p
.
Now let i
be an individual of class C
, which occurs two times in a json file so that in both the occurrences the property p
is present, with values respectively o
and o'
. When the DefaultInstanceBuilder
encounter the second occurrence of i
during the parsing of the json file, it throws a JsonDeserializationException
๐
Encountered multiple values of property
However, if o
and o'
are equals the single value constraint is not actually violated. In such a cases I think that avoiding to throw the exception would make the api more robust against strang but correct json files.
This might require switching from JSONLD-Java, which currently supports only 1.0 and its development has been lagging recently, to Titanium.
A corresponding JSONLD-Java issue is tracked under jsonld-java/jsonld-java#315
As a user, I want to be able to serialize the Java objects into JSON-LD with @context
attribute. This way, even applications without support for JSON-LD could understand the output.
Allowing the specification and handling of IRI aliases, e.g. https://www.w3.org/ns/activitystreams#inbox being an alias of https://www.w3.org/ns/ldp#inbox.
As a user, I want to be able to mark an attribute as read-only/write-only. Such attributes could not be deserialized/serialized.
JB4JSON-LD should be able to deserialize an object when an abstract return type is specified.
This would mean that the most specific concrete implementation matching the object's types whould be found and the JSON-LD would be deserialized as it.
For instance, consider the classes:
@OWLClass(iri = "A")
interface A {}
@OWLClass(iri = "B")
class B implements A {}
Then calling
A result = deserializer.deserialize(data, A.class);
on JSON-LD looking like this:
{
"@type": ["A", "B"]
}
Should result in result
being of type B
.
Since JOPA now supports mapping enum constants to individuals based on the OWL ObjectOneOf, JB4JSON-LD should support it as well.
This way, serialization of an enum constant mapped to an individual would produce an object with identifier and similarly, deserialization of an individual would match it to target enum constant based on the mapped individual.
As a user, I sometimes use the same attribute name for mapping different properties in the object model. This is problematic for serialization as it currently leads to an AmbiguousTermMappingException
. Instead, JSON-LD allows to use embedded contexts that locally override mapping of terms.
JB4JSON-LD should support this. An alternative is implementation of #41 .
When a JSON-LD object references another object via a unmapped property, the deserializer is not able to put this reference value into the @Properties
field value.
This is related to Enhancement #5 , as the reference will have to be deserialized so that only its IRI is put into the properties map.
When serializing a graph where an embedded context is generated for an instance (let's call it A) which has a reference to a collection of further objects, JB4JSON-LD attempts to add the embedded context to the collection node, causing the following exception:
java.lang.UnsupportedOperationException: Prepending items is not supported by this composite node.
at cz.cvut.kbss.jsonld.serialization.model.CompositeNode.prependItem(CompositeNode.java:45)
at cz.cvut.kbss.jsonld.serialization.JsonLdTreeBuilder.closeObject(JsonLdTreeBuilder.java:86)
at cz.cvut.kbss.jsonld.serialization.JsonLdTreeBuilder.closeCollection(JsonLdTreeBuilder.java:129)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.closeCollection(ObjectGraphTraverser.java:221)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverseCollection(ObjectGraphTraverser.java:78)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverse(ObjectGraphTraverser.java:64)
at cz.cvut.kbss.jsonld.serialization.serializer.compact.ObjectPropertyValueSerializer.serialize(ObjectPropertyValueSerializer.java:40)
at cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingObjectPropertyValueSerializer.serialize(ContextBuildingObjectPropertyValueSerializer.java:19)
at cz.cvut.kbss.jsonld.serialization.JsonLdTreeBuilder.visitAttribute(JsonLdTreeBuilder.java:110)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.visitAttribute(ObjectGraphTraverser.java:213)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.serializeFields(ObjectGraphTraverser.java:116)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverseSingular(ObjectGraphTraverser.java:94)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverse(ObjectGraphTraverser.java:66)
at cz.cvut.kbss.jsonld.serialization.serializer.compact.ObjectPropertyValueSerializer.serialize(ObjectPropertyValueSerializer.java:40)
at cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingObjectPropertyValueSerializer.serialize(ContextBuildingObjectPropertyValueSerializer.java:19)
at cz.cvut.kbss.jsonld.serialization.JsonLdTreeBuilder.visitAttribute(JsonLdTreeBuilder.java:110)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.visitAttribute(ObjectGraphTraverser.java:213)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.serializeFields(ObjectGraphTraverser.java:116)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverseSingular(ObjectGraphTraverser.java:94)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverse(ObjectGraphTraverser.java:66)
at cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser.traverse(ObjectGraphTraverser.java:57)
at cz.cvut.kbss.jsonld.serialization.ContextBuildingJsonLdSerializer.buildJsonTree(ContextBuildingJsonLdSerializer.java:82)
at cz.cvut.kbss.jsonld.serialization.JsonLdSerializer.serialize(JsonLdSerializer.java:79)
Using cz.cvut.kbss.jsonld.jackson.JsonLdModule.JsonLdModule to configure the jackson object mapper in a spring boot application i got the following error
java.lang.NoClassDefFoundError: cz/cvut/kbss/jopa/model/MultilingualString
cz.cvut.kbss.jsonld.deserialization.DefaultInstanceBuilder.openCollection(DefaultInstanceBuilder.java:156)
cz.cvut.kbss.jsonld.deserialization.expanded.CollectionDeserializer.processValue(CollectionDeserializer.java:48)
cz.cvut.kbss.jsonld.deserialization.expanded.ObjectDeserializer.processValue(ObjectDeserializer.java:57)
cz.cvut.kbss.jsonld.deserialization.expanded.ExpandedJsonLdDeserializer.deserialize(ExpandedJsonLdDeserializer.java:51)
cz.cvut.kbss.jsonld.jackson.deserialization.JacksonJsonLdDeserializer.deserialize(JacksonJsonLdDeserializer.java:62)
com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:195)
com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:21)
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218)
com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3267)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:239)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)
org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:104)
org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:998)
org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:981)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:741)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:714)
org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:602)
I just included
<dependency> <groupId>cz.cvut.kbss.jsonld</groupId> <artifactId>jb4jsonld-jackson</artifactId> <version>0.8.2</version> </dependency>
May be i need to import some other jopa module?
Instances of java.util.Date
should be serialized as the number of milliseconds since epoch and it should be possible to read them back into java.util.Date
objects again.
It would be nice to be able to deserialize full blown objects as values of identifier-base object property. For example
{
"@id": "http://krizik.felk.cvut.cz/ontologies/jb4jsonld#UNSC",
"@type": "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/Organization",
"brands": [
"Spartan-II",
"Mjolnir IV"
],
"http://purl.org/dc/terms/created": "Mon Aug 01 10:43:04 CEST 2016",
"http://www.w3.org/2000/01/rdf-schema#label": "UNSC"
}
Deserialize as value of:
...
@OWLObjectProperty(iri = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/isMemberOf")
private URI employer; // Would be http://krizik.felk.cvut.cz/ontologies/jb4jsonld#UNSC
...
This would simulate the application working with a smaller model than that available in the JSON-LD data.
As a user, I want to be able to serialize/deserialize enum values to/from JSON-LD.
JOPA allows to declare namespaces (using @Namespace
annotation) to shorted IRIs when mapping classes and attributes. JB4JSON-LD needs to be able to resolve the namespaces and output full IRIs into the JSON-LD.
I'm not sure if a github issue is the best place to discuss this, so feel free to close this if you feel it's the wrong place for this discussion, but...
How would you recommend handling a property such as https://www.w3.org/TR/activitystreams-vocabulary/#dfn-url where the Range can be either an xsd:anyURI or a Link object, or https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attachment where the Range can be either Object or Link.
Many of the properties in ActivityStreams4J are defined as java.lang.Object for this reason, but this obviously reduces the amount of type information avaliable and therefore causes UnknownPropertyException.
Any suggestions would be greatly appreciated.
I defined a ParentClass
and two subclasses ChildClassA
and ChildClassB
. ParentClass
has a single field, annotated with @id
, whereas the child classes has no additional fields.
@OWLClass(iri = "http://www.example.org/parent")
public static class ParentClass {
@Id
private String id;
public ParentClass() {
this.id = "http://noid.org";
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
}
@OWLClass(iri = "http://www.example.org/childa")
public static class ChildClassA extends ParentClass {
}
@OWLClass(iri = "http://www.example.org/childb")
public static class ChildClassB extends ParentClass {
}
As a user, I want to be able to specify the format of a value per attribute and not globally, as it is implemented now.
This would function similarly as JsonFormat
in Jackson.
Spring Boot 3.2.0 changed the structure of the JAR archive produced by their Maven plugin. This causes JB4JSON-LD's ClasspathScanner
to throw exceptions when scanning for deserialization candidate types.
An assertion fails when JsonLdProcessor.expand returns an empty list in JacksonJsonLdDeserializer::deserialize if the input is not expandable or valid jsonld.
java.lang.AssertionError
at cz.cvut.kbss.jsonld.deserialization.expanded.ExpandedJsonLdDeserializer.deserialize(ExpandedJsonLdDeserializer.java:42)
at cz.cvut.kbss.jsonld.jackson.deserialization.JacksonJsonLdDeserializer.deserialize(JacksonJsonLdDeserializer.java:63)
at cz.cvut.kbss.jsonld.jackson.deserialization.JacksonJsonLdDeserializer.deserializeWithType(JacksonJsonLdDeserializer.java:102)
An exception would likely be better in this case to allow for logical error handling in downstream applications.
As a user, I sometimes find the default (de)serialization behavior of JB4JSON-LD unsuitable for my requirements. I want to be able to override the default behavior using my own (de)serializer. This overriding should be possible on class and field level.
Similar feature is available in Jackson via the @JsonSerialize
and @JsonDeserialize
annotations.
As a user, I want to be able to reference external contexts in a JSON-LD document serialization. This could reduce the size of the serialization output significantly and allow centralized management of term mapping.
As a user, I want to be able to mark entity attributes as "ignored". Such attributes should be skipped in serialization. Consider whether such attributes should be ignored on deserialization as well.
As a developer, I want to be able to make JSON-LD output as close to plain JSON as possible. This should include the ability to serialize individuals (plain identifier object property values as well as enum constants mapped to individuals) as string with info about the value being in identifier in the context.
For example, currently, an individual is serialized as an object with id:
{
"@context": {
"attribute": "http://example.org/attribute"
},
"attribute": {
"@id": "http://www.w3.org/2002/07/owl#ObjectProperty"
}
}
Instead, it should be possible to configure the serialization (with context) so that the output is as follows:
{
"@context": {
"attribute": {
"@id": "http://example.org/attribute",
"@type": "@id"
}
},
"attribute": "http://www.w3.org/2002/07/owl#ObjectProperty"
}
This should make it easier for clients to digest the JSON-LD. Note that this will not have any influence on deserialization and serialization without context.
Similar to JOPA, an entity can have an object property value which is not another entity, but just an identifier (IRI) of another individual, which is not mapped by the object model. JB4JSON-LD should handle this.
E.g.
...
@OWLObjectProperty(iri = "http://onto.fel.cvut.cz/ontologies/form/has-answer-origin")
private URI origin;
...
I have the following hierarchy of @OWLClass
es
@id
@OWLClass(iri = "http://www.example.org/parent")
public class ParentClass implements Serializable {
@Id
protected String id;
public void setId(final String id) {
this.id = id;
}
public String getId() {
return id;
}
}
@OWLClass(iri = "http://www.example.org/childa")
public class ChildClassA extends ParentClass implements Serializable {
}
@OWLClass(iri = "http://www.example.org/childb")
public class ChildClassB extends ParentClass implements Serializable {
}
When deserializing an object of class ChildClassA
but using a reader for ParentClass
, the deserializer correctly return on object of class ChildClassA
. Here follows the test
@Test
public void shouldDeserializationReturnMostSpecificSubclass() throws JsonProcessingException {
final ChildClassA a = new ChildClassA();
a.setId("http://example.com/childa/a");
final String serialized = "{\"@id\":\"http://example.com/childa/a\",\"@type\":[\"http://www.example.org/childa\",\"http://www.example.org/parent\",\"http://www.example.org/grandparent\"]}";
final ObjectReader r = jsonLdObjectMapper().readerFor(ParentClass.class);
final ParentClass deserialized = r.readValue(serialized);
assertEquals(a.getId(), deserialized.getId());
assertTrue(deserialized instanceof ChildClassA);
}
The project is compiled with maven and tests is run by the maven surefire plugin. However, I decided to pack the class hiararchy above in a standalone maven artifact, and import the same artifact in another maven project by declaring it as dependency. The same test above, moved in this project which does not contains the hierarchy sources but just include it as dependency, fails because the deserializer returns an object of class ParentClass
As a user, I want JB4JSON-LD to serialize annotation property values as objects in case they represent individual references.
That is, if the annotation property value is a URI/URL, it should be serialized as an object with a single attribute - @id
.
Java objects with empty properties (i.e. empty collections or null values for simple java fields) are serialized to jsonld by empty array [] and empty objects {}. This is unnecessary and makes jsonld file hard to read in case where there are many empty properties.
An example of an annotated class and respective jsonld file is in attachment. The redundant part of jsonld is:
"form:has-preceding-question": [],
"form:has-question-origin": {}
It would be sufficient to exclude serialization of properties form:has-preceding-question, form:has-question-origin from the final output.
A number of valid activitystreams/jsonld tests in ActivityStreams4J error with AssertionErrors from JB4JSONLD in a variety of places:
I can provide specific examples of inputs if necessary, but it might be easier for you to clone ActivityStreams4J and run the tests yourself to be able to debug them, or look at the assertion errors from a recent build (please ignore the tests that fail with errors other than java.lang.AssertionError).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.