From 3d4460ade8b802826f2ce12ba26288984a966f3b Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 28 Mar 2023 10:54:22 +0200 Subject: [PATCH 01/15] [Fix] Fix an issue with serializing collections of enum constants. --- .../jsonld/common/BeanClassProcessor.java | 5 +--- .../cz/cvut/kbss/jsonld/common/EnumUtil.java | 15 ++++++++++++ .../ObjectPropertyValueSerializer.java | 10 ++------ .../traversal/ObjectGraphTraverser.java | 16 ++++++++++--- .../kbss/jsonld/environment/Vocabulary.java | 1 + .../jsonld/environment/model/Attribute.java | 23 ++++++++++++++++-- .../environment/model/OwlPropertyType.java | 2 +- .../CompactedJsonLdSerializerTest.java | 17 +++++++++++++ .../ContextBuildingJsonLdSerializerTest.java | 21 ++++++++++++++++ .../JsonLdSerializerTestBase.java | 11 +++++++++ .../traversal/ObjectGraphTraverserTest.java | 24 +++++++++++++++++-- .../util/BufferedJsonGenerator.java | 1 + 12 files changed, 126 insertions(+), 20 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java b/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java index dcafc87..c1a9a72 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java +++ b/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java @@ -22,8 +22,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.net.URI; -import java.net.URL; import java.util.*; public class BeanClassProcessor { @@ -248,11 +246,10 @@ public static void verifyPropertiesFieldType(Field field) { /** * Checks whether the specified type is a valid identifier type. - *

- * Valid identifiers in JOPA are: {@link URI}, {@link URL}, and {@link String}. * * @param cls Class to check * @return {@code true} if the specified class can be used as identifier field type, {@code false} otherwise + * @see PersistenceProperties#IDENTIFIER_TYPES */ public static boolean isIdentifierType(Class cls) { return PersistenceProperties.IDENTIFIER_TYPES.contains(cls); diff --git a/src/main/java/cz/cvut/kbss/jsonld/common/EnumUtil.java b/src/main/java/cz/cvut/kbss/jsonld/common/EnumUtil.java index ae436b7..596b088 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/common/EnumUtil.java +++ b/src/main/java/cz/cvut/kbss/jsonld/common/EnumUtil.java @@ -1,6 +1,7 @@ package cz.cvut.kbss.jsonld.common; import cz.cvut.kbss.jopa.model.annotations.Individual; +import cz.cvut.kbss.jsonld.exception.InvalidEnumMappingException; import cz.cvut.kbss.jsonld.exception.JsonLdException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,6 +18,20 @@ public class EnumUtil { private static final Logger LOG = LoggerFactory.getLogger(EnumUtil.class); + /** + * Resolves an individual mapped by the specified enum constant. + *

+ * This method looks for the value of the {@link Individual} annotation. + * + * @param value Value to map to individual + * @return Matching individual identifier + * @throws InvalidEnumMappingException When no matching individual is found + */ + public static String resolveMappedIndividual(Enum value) { + return findMatchingConstant(value.getDeclaringClass(), (e, iri) -> e == value, (e, iri) -> iri).orElseThrow( + () -> new InvalidEnumMappingException("Missing individual mapping for enum constant " + value)); + } + /** * Finds an enum constant matching the specified filtering predicate and transforms it using the specified mapper. *

diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java index 768d3c7..258a0d6 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java @@ -14,7 +14,6 @@ import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.common.EnumUtil; -import cz.cvut.kbss.jsonld.exception.InvalidEnumMappingException; import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; @@ -42,15 +41,10 @@ public JsonNode serialize(Object value, SerializationContext ctx) { return null; } - private JsonNode serializeEnumConstant(Enum constant, SerializationContext ctx) { - final String iri = resolveMappedIndividual(constant); + private static JsonNode serializeEnumConstant(Enum constant, SerializationContext ctx) { + final String iri = EnumUtil.resolveMappedIndividual(constant); final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); node.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, iri)); return node; } - - private String resolveMappedIndividual(Enum value) { - return EnumUtil.findMatchingConstant(value.getDeclaringClass(), (e, iri) -> e == value, (e, iri) -> iri).orElseThrow( - () -> new InvalidEnumMappingException("Missing individual mapping for enum constant " + value)); - } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java index 6fecc27..9291fdc 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java @@ -14,6 +14,7 @@ import cz.cvut.kbss.jsonld.common.BeanAnnotationProcessor; import cz.cvut.kbss.jsonld.common.BeanClassProcessor; +import cz.cvut.kbss.jsonld.common.EnumUtil; import cz.cvut.kbss.jsonld.common.IdentifierUtil; import cz.cvut.kbss.jsonld.exception.MissingIdentifierException; @@ -88,7 +89,7 @@ void traverseSingular(SerializationContext ctx) { } openInstance(ctx); visitIdentifier(ctx); - if (!BeanClassProcessor.isIdentifierType(ctx.getValue().getClass()) && firstEncounter) { + if (shouldTraverseObject(ctx, firstEncounter)) { visitTypes(ctx); serializeFields(ctx); serializePropertiesField(ctx); @@ -96,6 +97,11 @@ void traverseSingular(SerializationContext ctx) { closeInstance(ctx); } + private boolean shouldTraverseObject(SerializationContext ctx, boolean firstEncounter) { + return firstEncounter && !BeanClassProcessor.isIdentifierType(ctx.getValue().getClass()) && + !ctx.getValue().getClass().isEnum(); + } + private void serializeFields(SerializationContext ctx) { final Object instance = ctx.getValue(); final List fieldsToSerialize = @@ -176,15 +182,19 @@ public void closeInstance(SerializationContext ctx) { public void visitIdentifier(SerializationContext ctx) { final Object identifier = ctx.getValue(); + final Class idCls = identifier.getClass(); final String id; final SerializationContext idContext; - if (BeanClassProcessor.isIdentifierType(identifier.getClass())) { + if (BeanClassProcessor.isIdentifierType(idCls)) { id = identifier.toString(); idContext = serializationContextFactory.createForIdentifier(null, id, ctx); + } else if (idCls.isEnum()) { + id = EnumUtil.resolveMappedIndividual((Enum) identifier); + idContext = serializationContextFactory.createForIdentifier(null, id, ctx); } else { id = resolveIdentifier(identifier); idContext = serializationContextFactory.createForIdentifier( - BeanAnnotationProcessor.getIdentifierField(identifier.getClass()).orElse(null), id, ctx); + BeanAnnotationProcessor.getIdentifierField(idCls).orElse(null), id, ctx); knownInstances.put(identifier, id); } visitor.visitIdentifier(idContext); diff --git a/src/test/java/cz/cvut/kbss/jsonld/environment/Vocabulary.java b/src/test/java/cz/cvut/kbss/jsonld/environment/Vocabulary.java index b472dff..f7a260e 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/environment/Vocabulary.java +++ b/src/test/java/cz/cvut/kbss/jsonld/environment/Vocabulary.java @@ -47,6 +47,7 @@ public class Vocabulary { public static final String PASSWORD = DEFAULT_PREFIX + "password"; public static final String NUMBER_OF_PEOPLE_INVOLVED = DEFAULT_PREFIX + "numberOfPeopleInvolved"; public static final String HAS_PROPERTY_TYPE = DEFAULT_PREFIX + "hasPropertyType"; + public static final String HAS_PLURAL_PROPERTY_TYPE = DEFAULT_PREFIX + "hasPluralPropertyType"; public static final String CHANGED_VALUE = DEFAULT_PREFIX + "changedValue"; diff --git a/src/test/java/cz/cvut/kbss/jsonld/environment/model/Attribute.java b/src/test/java/cz/cvut/kbss/jsonld/environment/model/Attribute.java index c6c16f0..3605f1b 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/environment/model/Attribute.java +++ b/src/test/java/cz/cvut/kbss/jsonld/environment/model/Attribute.java @@ -19,6 +19,10 @@ public class Attribute implements GeneratesRdf { @OWLObjectProperty(iri = Vocabulary.HAS_PROPERTY_TYPE) private OwlPropertyType propertyType; + @Enumerated(EnumType.OBJECT_ONE_OF) + @OWLObjectProperty(iri = Vocabulary.HAS_PLURAL_PROPERTY_TYPE) + private Set pluralPropertyType; + @Override public URI getUri() { return uri; @@ -36,13 +40,28 @@ public void setPropertyType(OwlPropertyType propertyType) { this.propertyType = propertyType; } + public Set getPluralPropertyType() { + return pluralPropertyType; + } + + public void setPluralPropertyType(Set pluralPropertyType) { + this.pluralPropertyType = pluralPropertyType; + } + @Override public void toRdf(Model model, ValueFactory vf, Set visited) { if (visited.contains(getUri())) { return; } model.add(vf.createIRI(uri.toString()), RDF.TYPE, vf.createIRI(Vocabulary.ATTRIBUTE)); - model.add(vf.createIRI(uri.toString()), vf.createIRI(Vocabulary.HAS_PROPERTY_TYPE), - vf.createIRI(OwlPropertyType.getMappedIndividual(propertyType))); + if (propertyType != null) { + model.add(vf.createIRI(uri.toString()), vf.createIRI(Vocabulary.HAS_PROPERTY_TYPE), + vf.createIRI(OwlPropertyType.getMappedIndividual(propertyType))); + } + if (getPluralPropertyType() != null) { + getPluralPropertyType().forEach( + t -> model.add(vf.createIRI(uri.toString()), vf.createIRI(Vocabulary.HAS_PLURAL_PROPERTY_TYPE), + vf.createIRI(OwlPropertyType.getMappedIndividual(t)))); + } } } diff --git a/src/test/java/cz/cvut/kbss/jsonld/environment/model/OwlPropertyType.java b/src/test/java/cz/cvut/kbss/jsonld/environment/model/OwlPropertyType.java index 2c021cf..5733873 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/environment/model/OwlPropertyType.java +++ b/src/test/java/cz/cvut/kbss/jsonld/environment/model/OwlPropertyType.java @@ -12,7 +12,7 @@ public enum OwlPropertyType { @Individual(iri = OWL.OBJECT_PROPERTY) OBJECT_PROPERTY; - static String getMappedIndividual(OwlPropertyType constant) { + public static String getMappedIndividual(OwlPropertyType constant) { switch (constant) { case ANNOTATION_PROPERTY: return OWL.ANNOTATION_PROPERTY; diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializerTest.java index f34fe5d..96b67d0 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializerTest.java @@ -195,4 +195,21 @@ void serializationSerializesMultilingualStringWithLanguageLessValue() throws Exc assertTrue(result.isPresent()); assertEquals(name.get(), result.get().get(JsonLd.VALUE)); } + + @Test + void serializationSerializesRootCollectionOfEnumConstantsMappedToIndividualsAsArrayOfIndividuals() throws Exception { + final List value = Arrays.asList(OwlPropertyType.values()); + + sut.serialize(new LinkedHashSet<>(value)); + Object jsonObject = JsonUtils.fromString(jsonWriter.getResult()); + assertInstanceOf(List.class, jsonObject); + final List lst = (List) jsonObject; + assertEquals(value.size(), lst.size()); + for (int i = 0; i < value.size(); i++) { + assertInstanceOf(Map.class, lst.get(i)); + final Map element = (Map) lst.get(i); + assertThat(element, hasKey(JsonLd.ID)); + assertEquals(OwlPropertyType.getMappedIndividual(value.get(i)), element.get(JsonLd.ID)); + } + } } diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java index 0bd5e37..2aeb947 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java @@ -1,5 +1,6 @@ package cz.cvut.kbss.jsonld.serialization; +import com.github.jsonldjava.utils.JsonUtils; import cz.cvut.kbss.jopa.model.MultilingualString; import cz.cvut.kbss.jopa.model.annotations.Id; import cz.cvut.kbss.jopa.model.annotations.OWLClass; @@ -267,4 +268,24 @@ void serializationUsesRegisteredIdentifierTermWhenSerializingPlainIdentifierObje assertThat(country, hasKey("uri")); assertEquals(instance.getCountry().toString(), country.get("uri")); } + + @Test + void serializationSerializesRootCollectionOfEnumConstantsMappedToIndividualsAsArrayOfIndividuals() throws Exception { + final List value = Arrays.asList(OwlPropertyType.values()); + + sut.serialize(new LinkedHashSet<>(value)); + Object jsonObject = JsonUtils.fromString(jsonWriter.getResult()); + assertInstanceOf(Map.class, jsonObject); + final Map map = (Map) jsonObject; + assertThat(map, hasKey(JsonLd.GRAPH)); + assertInstanceOf(List.class, map.get(JsonLd.GRAPH)); + final List lst = (List) map.get(JsonLd.GRAPH); + assertEquals(value.size(), lst.size()); + for (int i = 0; i < value.size(); i++) { + assertInstanceOf(Map.class, lst.get(i)); + final Map element = (Map) lst.get(i); + assertThat(element, hasKey(JsonLd.ID)); + assertEquals(OwlPropertyType.getMappedIndividual(value.get(i)), element.get(JsonLd.ID)); + } + } } \ No newline at end of file diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdSerializerTestBase.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdSerializerTestBase.java index 092854c..a693e46 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdSerializerTestBase.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdSerializerTestBase.java @@ -419,4 +419,15 @@ void serializationSerializesEnumConstantMappedToIndividualAsIndividual() throws final Model actual = readJson(jsonWriter.getResult()); assertThat(actual, isIsomorphic(expected)); } + + @Test + void serializationSerializesAttributeWithCollectionOfEnumConstantsMappedToIndividualsAsArrayOfIndividuals() throws Exception { + final Attribute instance = new Attribute(); + instance.setUri(Generator.generateUri()); + instance.setPluralPropertyType(new HashSet<>(Arrays.asList(OwlPropertyType.values()))); + sut.serialize(instance); + final Model expected = toRdf(instance); + final Model actual = readJson(jsonWriter.getResult()); + assertThat(actual, isIsomorphic(expected)); + } } diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java index 9ab3787..bdfb4f0 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java @@ -16,6 +16,7 @@ import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; import cz.cvut.kbss.jopa.model.annotations.Types; +import cz.cvut.kbss.jopa.vocabulary.OWL; import cz.cvut.kbss.jopa.vocabulary.RDFS; import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.annotation.JsonLdAttributeOrder; @@ -29,6 +30,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -76,7 +78,8 @@ private static SerializationContext ctx(String attId, Field field, T valu private void verifyUserFieldsVisited(User user) throws NoSuchFieldException { verify(visitor).visitIdentifier( - new SerializationContext<>(JsonLd.ID, Person.class.getDeclaredField("uri"), user.getUri().toString(), DummyJsonLdContext.INSTANCE)); + new SerializationContext<>(JsonLd.ID, Person.class.getDeclaredField("uri"), user.getUri().toString(), + DummyJsonLdContext.INSTANCE)); verify(visitor).visitAttribute(ctx(Vocabulary.FIRST_NAME, Person.getFirstNameField(), user.getFirstName())); verify(visitor).visitAttribute(ctx(Vocabulary.LAST_NAME, Person.getLastNameField(), user.getLastName())); verify(visitor).visitAttribute(ctx(Vocabulary.USERNAME, User.getUsernameField(), user.getUsername())); @@ -102,7 +105,10 @@ void traverseRecognizesAlreadyVisitedInstances() throws Exception { verify(visitor).openObject(ctx(null, null, employee)); verify(visitor).openObject(ctx(Vocabulary.HAS_MEMBER, Organization.getEmployeesField(), employee)); verify(visitor).visitTypes(new SerializationContext<>(JsonLd.TYPE, User.class.getDeclaredField("types"), - new HashSet<>(Arrays.asList(Vocabulary.PERSON, Vocabulary.USER, Vocabulary.EMPLOYEE)), DummyJsonLdContext.INSTANCE)); + new HashSet<>( + Arrays.asList(Vocabulary.PERSON, Vocabulary.USER, + Vocabulary.EMPLOYEE)), + DummyJsonLdContext.INSTANCE)); } @Test @@ -328,4 +334,18 @@ void traverseDoesNotOpenObjectWhenVisitObjectReturnedFalse() { verify(visitor).visitObject(ctx(null, null, p)); verify(visitor, never()).openObject(any()); } + + @Test + void traverseSingularEnumConstantOpensObjectAndAddsOnlyIdentifierToIt() { + final SerializationContext ctx = + new SerializationContext<>(OwlPropertyType.OBJECT_PROPERTY, DummyJsonLdContext.INSTANCE); + traverser.traverse(ctx); + verify(visitor).openObject(ctx); + final ArgumentCaptor> captor = ArgumentCaptor.forClass(SerializationContext.class); + verify(visitor).visitIdentifier(captor.capture()); + assertEquals(OWL.OBJECT_PROPERTY, captor.getValue().getValue()); + assertEquals(JsonLd.ID, captor.getValue().getTerm()); + verify(visitor, never()).visitAttribute(any()); + verify(visitor, never()).visitTypes(any()); + } } diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/util/BufferedJsonGenerator.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/util/BufferedJsonGenerator.java index c16eb05..386737a 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/util/BufferedJsonGenerator.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/util/BufferedJsonGenerator.java @@ -56,6 +56,7 @@ public void writeObjectStart() { public void writeObjectEnd() { buffer.append('}'); nodes.pop(); + this.firstAttribute = false; } @Override From ea3339511ba2e02f2ac9f889f24334efcf522b09 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 28 Mar 2023 10:57:16 +0200 Subject: [PATCH 02/15] Ensure deserialization of collections of enum constants works. --- .../expanded/ExpandedJsonLdDeserializerTest.java | 2 ++ src/test/resources/objectWithReferenceMappedToEnum.json | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/cz/cvut/kbss/jsonld/deserialization/expanded/ExpandedJsonLdDeserializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/deserialization/expanded/ExpandedJsonLdDeserializerTest.java index 8ec6edf..d3466ef 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/deserialization/expanded/ExpandedJsonLdDeserializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/deserialization/expanded/ExpandedJsonLdDeserializerTest.java @@ -799,5 +799,7 @@ void deserializeSupportsMappingIndividualToEnumConstant() throws Exception { final Attribute result = sut.deserialize(input, Attribute.class); assertNotNull(result); assertEquals(OwlPropertyType.DATATYPE_PROPERTY, result.getPropertyType()); + assertThat(result.getPluralPropertyType(), + hasItems(OwlPropertyType.ANNOTATION_PROPERTY, OwlPropertyType.OBJECT_PROPERTY)); } } diff --git a/src/test/resources/objectWithReferenceMappedToEnum.json b/src/test/resources/objectWithReferenceMappedToEnum.json index f2df375..f638015 100644 --- a/src/test/resources/objectWithReferenceMappedToEnum.json +++ b/src/test/resources/objectWithReferenceMappedToEnum.json @@ -5,5 +5,10 @@ "@id": "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/Attribute#instance-1587729056", "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/hasPropertyType": { "@id": "http://www.w3.org/2002/07/owl#DatatypeProperty" - } + }, + "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/hasPluralPropertyType": [{ + "@id": "http://www.w3.org/2002/07/owl#AnnotationProperty" + }, { + "@id": "http://www.w3.org/2002/07/owl#ObjectProperty" + }] } \ No newline at end of file From 8ad8bc0d8e7947096db7cebb031d5adf5b073f6e Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 28 Mar 2023 12:42:29 +0200 Subject: [PATCH 03/15] [0.12.1] Bump version, update changelog. --- CHANGELOG.md | 3 +++ pom.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79d301f..4fe78bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # JB4JSON-LD Changelog +## 0.12.1 - 2023-03-28 +- Fix an issue with serialization of a collection of enum constants mapped to individuals. + ## 0.12.0 - 2023-03-20 - Implement support for mapping Java enum constants to reference nodes (nodes with `@id`) (Enhancement #48). - Dependency updates: JOPA 0.21.0, JUnit, Mockito. diff --git a/pom.xml b/pom.xml index e83a492..d66771c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ cz.cvut.kbss.jsonld jb4jsonld - 0.12.0 + 0.12.1 JB4JSON-LD Java Binding for JSON-LD allows serialization and deserialization of Java POJOs to/from JSON-LD. This is the core implementation, which has to be integrated with Jackson, Jersey etc. From 07206c023be871f1044091672750173b0c1f852e Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 30 Mar 2023 08:51:06 +0200 Subject: [PATCH 04/15] [Bug #51] Add test reproducing the issue. --- .../ContextBuildingJsonLdSerializerTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java index 2aeb947..7d53476 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java @@ -229,6 +229,10 @@ void serializationCreatesEmbeddedContextToOverrideIncompatibleTermMapping() thro instance.organization = Generator.generateOrganization(); final Map json = serializeAndRead(instance); + verifyEmbeddedContext(json); + } + + private void verifyEmbeddedContext(Map json) { assertThat(json, hasKey(JsonLd.CONTEXT)); assertInstanceOf(Map.class, json.get(JsonLd.CONTEXT)); final Map context = (Map) json.get(JsonLd.CONTEXT); @@ -288,4 +292,21 @@ void serializationSerializesRootCollectionOfEnumConstantsMappedToIndividualsAsAr assertEquals(OwlPropertyType.getMappedIndividual(value.get(i)), element.get(JsonLd.ID)); } } + + /** + * Bug #51 + */ + @Test + void serializationCreatesEmbeddedContextOnCorrectLevel() throws Exception { + final StudyWithTitle instance = new StudyWithTitle(); + instance.uri = Generator.generateUri(); + instance.name = "Test study"; + instance.organization = Generator.generateOrganization(); + instance.organization.addEmployee(Generator.generateEmployee()); + instance.organization.addEmployee(Generator.generateEmployee()); + instance.organization.getEmployees().forEach(e -> e.setEmployer(instance.organization)); + + final Map json = serializeAndRead(instance); + verifyEmbeddedContext(json); + } } \ No newline at end of file From 66553da61ef5ca9101ec9c056a8746aa3331d3d4 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 30 Mar 2023 09:17:59 +0200 Subject: [PATCH 05/15] [Bug #51] Fix the issue of attempting to add JSON-LD context to a collection node. --- .../cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java | 6 +++++- .../kbss/jsonld/serialization/JsonLdTreeBuilderTest.java | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java index 1854446..275fb78 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java @@ -85,6 +85,10 @@ public void closeObject(SerializationContext ctx) { if (!ctx.isCurrentEmpty()) { currentNode.prependItem(ctx.getContextNode()); } + closeCurrentNode(); + } + + private void closeCurrentNode() { currentNode.close(); if (!nodeStack.empty()) { this.currentNode = nodeStack.pop(); @@ -126,7 +130,7 @@ public void openCollection(SerializationContext> ctx) { @Override public void closeCollection(SerializationContext ctx) { assert currentNode instanceof CollectionNode; - closeObject(ctx); + closeCurrentNode(); } public CompositeNode getTreeRoot() { diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilderTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilderTest.java index a0b6028..869ccfd 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilderTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilderTest.java @@ -23,7 +23,6 @@ import cz.cvut.kbss.jsonld.environment.Vocabulary; import cz.cvut.kbss.jsonld.environment.model.*; import cz.cvut.kbss.jsonld.serialization.context.DummyJsonLdContext; -import cz.cvut.kbss.jsonld.serialization.context.MappingJsonLdContextFactory; import cz.cvut.kbss.jsonld.serialization.model.*; import cz.cvut.kbss.jsonld.serialization.serializer.LiteralValueSerializers; import cz.cvut.kbss.jsonld.serialization.serializer.compact.DefaultValueSerializer; From 4ba4fca9a5180ab2600c3e5abdc95252a76f8c13 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 30 Mar 2023 09:49:34 +0200 Subject: [PATCH 06/15] [0.12.2] Bump version, update changelog. --- CHANGELOG.md | 3 +++ pom.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe78bf..f17a758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # JB4JSON-LD Changelog +## 0.12.2 - 2023-03-30 +- Fix an issue with context embedding (Bug #51). + ## 0.12.1 - 2023-03-28 - Fix an issue with serialization of a collection of enum constants mapped to individuals. diff --git a/pom.xml b/pom.xml index d66771c..52dd372 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ cz.cvut.kbss.jsonld jb4jsonld - 0.12.1 + 0.12.2 JB4JSON-LD Java Binding for JSON-LD allows serialization and deserialization of Java POJOs to/from JSON-LD. This is the core implementation, which has to be integrated with Jackson, Jersey etc. From 600678ec3a4e74391a5945ac35dca2e7b9e29cd2 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 30 Mar 2023 13:31:20 +0200 Subject: [PATCH 07/15] [Enhancement #54] Add acceptance tests for the feature. --- .../ContextBuildingJsonLdSerializerTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java index 7d53476..a5af90d 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java @@ -7,8 +7,10 @@ import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; import cz.cvut.kbss.jopa.vocabulary.DC; +import cz.cvut.kbss.jopa.vocabulary.OWL; import cz.cvut.kbss.jopa.vocabulary.RDFS; import cz.cvut.kbss.jopa.vocabulary.XSD; +import cz.cvut.kbss.jsonld.ConfigParam; import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.common.IdentifierUtil; import cz.cvut.kbss.jsonld.environment.Generator; @@ -16,6 +18,7 @@ import cz.cvut.kbss.jsonld.environment.Vocabulary; import cz.cvut.kbss.jsonld.environment.model.*; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; +import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.eclipse.rdf4j.model.util.Models; @@ -309,4 +312,54 @@ void serializationCreatesEmbeddedContextOnCorrectLevel() throws Exception { final Map json = serializeAndRead(instance); verifyEmbeddedContext(json); } + + @Test + void serializationSerializesIndividualsAsStringWithExpandedTermDefinitionInContextWhenConfiguredTo() throws Exception { + sut.configuration().set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + final Attribute instance = new Attribute(); + instance.setUri(Generator.generateUri()); + instance.setPropertyType(OwlPropertyType.DATATYPE_PROPERTY); + instance.setPluralPropertyType( + new HashSet<>(Arrays.asList(OwlPropertyType.ANNOTATION_PROPERTY, OwlPropertyType.OBJECT_PROPERTY))); + + final Map json = serializeAndRead(instance); + assertThat(json, hasKey(JsonLd.CONTEXT)); + assertInstanceOf(Map.class, json.get(JsonLd.CONTEXT)); + final Map context = (Map) json.get(JsonLd.CONTEXT); + assertThat(context, hasKey("propertyType")); + final ObjectNode termDef = new ObjectNode("propertyType"); + termDef.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, Vocabulary.HAS_PROPERTY_TYPE)); + termDef.addItem(JsonNodeFactory.createStringLiteralNode(JsonLd.TYPE, JsonLd.ID)); + assertEquals(termDef, context.get("propertyType")); + assertThat(context, hasKey("pluralPropertyType")); + final ObjectNode pluralTermDef = new ObjectNode("pluralPropertyType"); + pluralTermDef.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, Vocabulary.HAS_PLURAL_PROPERTY_TYPE)); + pluralTermDef.addItem(JsonNodeFactory.createStringLiteralNode(JsonLd.TYPE, JsonLd.ID)); + assertEquals(pluralTermDef, context.get("pluralPropertyType")); + assertThat(json, hasKey("propertyType")); + assertEquals(OWL.DATATYPE_PROPERTY, json.get("propertyType")); + assertThat(json, hasKey("pluralPropertyType")); + assertInstanceOf(List.class, json.get("pluralPropertyType")); + assertThat((List) json.get("pluralPropertyType"), + hasItems(OWL.ANNOTATION_PROPERTY, OWL.OBJECT_PROPERTY)); + } + + @Test + void serializationSerializesPlainIdentifierAsStringWithExpandedTermDefinitionInContextWhenConfiguredTo() throws Exception { + sut.configuration().set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + final Organization instance = Generator.generateOrganization(); + instance.setCountry(URI.create("http://dbpedia.org/resource/Czech_Republic")); + + final Map json = serializeAndRead(instance); + assertThat(json, hasKey(JsonLd.CONTEXT)); + assertInstanceOf(Map.class, json.get(JsonLd.CONTEXT)); + final Map context = (Map) json.get(JsonLd.CONTEXT); + assertThat(context, hasKey("country")); + final ObjectNode termDef = new ObjectNode("country"); + termDef.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, Vocabulary.ORIGIN)); + termDef.addItem(JsonNodeFactory.createStringLiteralNode(JsonLd.TYPE, JsonLd.ID)); + assertThat(context, hasKey("country")); + assertEquals(termDef, context.get("country")); + assertEquals(instance.getCountry().toString(), json.get("country")); + } } \ No newline at end of file From 26b2b80a911caa94485c71813618f764fd816c8f Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 31 Mar 2023 10:24:31 +0200 Subject: [PATCH 08/15] [Enhancement #54] Implement serialization of individuals as string with extended term definition in context. --- .../java/cz/cvut/kbss/jsonld/ConfigParam.java | 10 ++- .../CompactedJsonLdSerializer.java | 13 ++-- .../ContextBuildingJsonLdSerializer.java | 7 +- .../serialization/JsonLdTreeBuilder.java | 12 ++++ .../jsonld/serialization/model/JsonNode.java | 5 +- .../serializer/LiteralValueSerializers.java | 17 ++++- .../ObjectGraphValueSerializers.java | 10 +++ .../serializer/ValueSerializers.java | 5 ++ .../compact/IndividualSerializer.java | 42 +++++++++++ .../ObjectPropertyValueSerializer.java | 10 --- .../ContextBuildingIndividualSerializer.java | 33 +++++++++ ...BuildingObjectPropertyValueSerializer.java | 25 ++++++- .../traversal/InstanceVisitor.java | 8 +++ .../traversal/ObjectGraphTraverser.java | 28 +++----- .../ContextBuildingJsonLdSerializerTest.java | 30 ++++---- .../compact/IndividualSerializerTest.java | 69 +++++++++++++++++++ .../ObjectPropertyValueSerializerTest.java | 42 +---------- ...dingObjectPropertyValueSerializerTest.java | 22 +++++- .../traversal/ObjectGraphTraverserTest.java | 25 +++---- 19 files changed, 302 insertions(+), 111 deletions(-) create mode 100644 src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java create mode 100644 src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java create mode 100644 src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializerTest.java diff --git a/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java b/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java index aae1c71..3abcea7 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java +++ b/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java @@ -99,7 +99,15 @@ public enum ConfigParam { *

* Also note that this format applies only to full datetime values. Date or time values have to be formatted per-attribute. */ - DATE_TIME_FORMAT("datetimeFormat"); + DATE_TIME_FORMAT("datetimeFormat"), + + /** + * Whether to serialize individuals using expanded term definition in context. + * + * This basically means that the individual's identifier is provided directly as a string and an expanded term + * definition is added into the context, specifying that the string is an identifier. + */ + SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION("serializeIndividualsUsingExpandedDefinition"); private final String name; diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializer.java index ccb1763..26c9984 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/CompactedJsonLdSerializer.java @@ -50,6 +50,7 @@ protected ValueSerializers initSerializers() { new LiteralValueSerializers(new DefaultValueSerializer(new MultilingualStringSerializer())); valueSerializers.registerIdentifierSerializer(new IdentifierSerializer()); valueSerializers.registerTypesSerializer(new TypesSerializer()); + valueSerializers.registerIndividualSerializer(new IndividualSerializer()); final TemporalSerializer ts = new TemporalSerializer(); valueSerializers.registerSerializer(LocalDate.class, ts); // Register the same temporal serializer for each of the types it supports (needed for key-based map access) @@ -72,12 +73,16 @@ protected JsonNode buildJsonTree(Object root) { final ObjectGraphTraverser traverser = new ObjectGraphTraverser(new SerializationContextFactory( DummyJsonLdContext.INSTANCE)); traverser.setRequireId(configuration().is(ConfigParam.REQUIRE_ID)); - final JsonLdTreeBuilder treeBuilder = - new JsonLdTreeBuilder( - new ObjectGraphValueSerializers(serializers, new ObjectPropertyValueSerializer(traverser)), - DummyJsonLdContext.INSTANCE); + final JsonLdTreeBuilder treeBuilder = initTreeBuilder(traverser); traverser.setVisitor(treeBuilder); traverser.traverse(root); return treeBuilder.getTreeRoot(); } + + private JsonLdTreeBuilder initTreeBuilder(ObjectGraphTraverser traverser) { + final ObjectPropertyValueSerializer opSerializer = new ObjectPropertyValueSerializer(traverser); + opSerializer.configure(configuration()); + return new JsonLdTreeBuilder(new ObjectGraphValueSerializers(serializers, opSerializer), + DummyJsonLdContext.INSTANCE); + } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializer.java index 3ab34f6..54bb3e1 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializer.java @@ -50,6 +50,7 @@ protected ValueSerializers initSerializers() { new LiteralValueSerializers(new ContextBuildingDefaultValueSerializer(mlsSerializer, mlsColSerializer)); valueSerializers.registerIdentifierSerializer(new ContextBuildingIdentifierSerializer()); valueSerializers.registerTypesSerializer(new ContextBuildingTypesSerializer()); + valueSerializers.registerIndividualSerializer(new ContextBuildingIndividualSerializer()); final ContextBuildingTemporalSerializer ts = new ContextBuildingTemporalSerializer(); valueSerializers.registerSerializer(LocalDate.class, ts); // Register the same temporal serializer for each of the types it supports (needed for key-based map access) @@ -96,9 +97,9 @@ private void ensureContextNodeNotPresent(CompositeNode root, JsonNode rootCtx private JsonLdTreeBuilder initTreeBuilder(ObjectGraphTraverser traverser, JsonLdContextFactory jsonLdContextFactory) { - return new JsonLdTreeBuilder(new ObjectGraphValueSerializers(serializers, - new ContextBuildingObjectPropertyValueSerializer( - traverser)), jsonLdContextFactory); + final ContextBuildingObjectPropertyValueSerializer opSerializer = new ContextBuildingObjectPropertyValueSerializer(traverser); + opSerializer.configure(configuration()); + return new JsonLdTreeBuilder(new ObjectGraphValueSerializers(serializers, opSerializer), jsonLdContextFactory); } private JsonNode buildObjectWithContextAndGraph(ObjectGraphTraverser traverser, JsonLdContext rootContext, diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java index 275fb78..4648069 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java @@ -43,6 +43,18 @@ public JsonLdTreeBuilder(ValueSerializers serializers, JsonLdContextFactory json this.jsonLdContextFactory = jsonLdContextFactory; } + @Override + public void visitIndividual(SerializationContext ctx) { + final ValueSerializer s = serializers.getIndividualSerializer(); + final JsonNode node = s.serialize(ctx.getValue(), ctx); + if (currentNode != null) { + currentNode.addItem(node); + } else { + assert node instanceof CompositeNode; + currentNode = (CompositeNode) node; + } + } + @Override public boolean visitObject(SerializationContext ctx) { if (serializers.hasCustomSerializer(ctx.getValue().getClass())) { diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/model/JsonNode.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/model/JsonNode.java index 81b4660..3aabcdf 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/model/JsonNode.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/model/JsonNode.java @@ -18,7 +18,6 @@ import cz.cvut.kbss.jsonld.serialization.JsonGenerator; import java.io.IOException; -import java.util.Objects; public abstract class JsonNode { @@ -31,8 +30,8 @@ public abstract class JsonNode { } public JsonNode(String name) { - this.name = Objects.requireNonNull(name); - this.valueNode = false; + this.name = name; + this.valueNode = name == null; } public String getName() { diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/LiteralValueSerializers.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/LiteralValueSerializers.java index 7472f18..0f47731 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/LiteralValueSerializers.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/LiteralValueSerializers.java @@ -34,11 +34,12 @@ public class LiteralValueSerializers implements ValueSerializers { private ValueSerializer> typesSerializer; + private ValueSerializer individualSerializer; + public LiteralValueSerializers(ValueSerializer defaultSerializer) { this.defaultSerializer = Objects.requireNonNull(defaultSerializer); } - @Override public boolean hasCustomSerializer(Class type) { return serializers.containsKey(type); @@ -81,8 +82,22 @@ public void registerTypesSerializer(ValueSerializer> typesSerializer this.typesSerializer = Objects.requireNonNull(typesSerializer); } + @Override + public ValueSerializer getIndividualSerializer() { + return individualSerializer; + } + + @Override + public void registerIndividualSerializer(ValueSerializer individualSerializer) { + this.individualSerializer = Objects.requireNonNull(individualSerializer); + } + @Override public void configure(Configuration configuration) { serializers.values().forEach(vs -> vs.configure(configuration)); + individualSerializer.configure(configuration); + identifierSerializer.configure(configuration); + typesSerializer.configure(configuration); + defaultSerializer.configure(configuration); } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializers.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializers.java index 5987614..36b25b1 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializers.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializers.java @@ -80,4 +80,14 @@ public ValueSerializer> getTypesSerializer() { public void registerTypesSerializer(ValueSerializer> typesSerializer) { serializers.registerTypesSerializer(typesSerializer); } + + @Override + public ValueSerializer getIndividualSerializer() { + return serializers.getIndividualSerializer(); + } + + @Override + public void registerIndividualSerializer(ValueSerializer individualSerializer) { + serializers.registerIndividualSerializer(individualSerializer); + } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ValueSerializers.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ValueSerializers.java index 5858979..b1a7109 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ValueSerializers.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/ValueSerializers.java @@ -13,6 +13,7 @@ package cz.cvut.kbss.jsonld.serialization.serializer; import cz.cvut.kbss.jsonld.common.Configurable; +import cz.cvut.kbss.jsonld.serialization.serializer.compact.IndividualSerializer; import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; import java.util.Optional; @@ -69,4 +70,8 @@ public interface ValueSerializers extends Configurable { ValueSerializer> getTypesSerializer(); void registerTypesSerializer(ValueSerializer> typesSerializer); + + ValueSerializer getIndividualSerializer(); + + void registerIndividualSerializer(ValueSerializer individualSerializer); } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java new file mode 100644 index 0000000..05dccf6 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java @@ -0,0 +1,42 @@ +package cz.cvut.kbss.jsonld.serialization.serializer.compact; + +import cz.cvut.kbss.jsonld.JsonLd; +import cz.cvut.kbss.jsonld.common.BeanClassProcessor; +import cz.cvut.kbss.jsonld.common.EnumUtil; +import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; +import cz.cvut.kbss.jsonld.serialization.model.JsonNode; +import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; +import cz.cvut.kbss.jsonld.serialization.serializer.ValueSerializer; +import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; + +/** + * Serializes individuals. + *

+ * That is, either a plain identifier value of an object property attribute or an enum constant mapped to an + * individual. + */ +public class IndividualSerializer implements ValueSerializer { + + @Override + public JsonNode serialize(Object value, SerializationContext ctx) { + assert BeanClassProcessor.isIdentifierType(value.getClass()) || value.getClass().isEnum(); + if (BeanClassProcessor.isIdentifierType(value.getClass())) { + final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); + node.addItem(JsonNodeFactory.createObjectIdNode(idAttribute(ctx), value)); + return node; + } else { + return serializeEnumConstant((Enum) value, ctx); + } + } + + private String idAttribute(SerializationContext ctx) { + return ctx.getJsonLdContext().getMappedTerm(JsonLd.ID).orElse(JsonLd.ID); + } + + protected JsonNode serializeEnumConstant(Enum constant, SerializationContext ctx) { + final String iri = EnumUtil.resolveMappedIndividual(constant); + final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); + node.addItem(JsonNodeFactory.createObjectIdNode(idAttribute(ctx), iri)); + return node; + } +} diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java index 258a0d6..0db24c4 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java @@ -34,17 +34,7 @@ public ObjectPropertyValueSerializer(ObjectGraphTraverser graphTraverser) { @Override public JsonNode serialize(Object value, SerializationContext ctx) { - if (value.getClass().isEnum()) { - return serializeEnumConstant((Enum) value, ctx); - } graphTraverser.traverse(ctx); return null; } - - private static JsonNode serializeEnumConstant(Enum constant, SerializationContext ctx) { - final String iri = EnumUtil.resolveMappedIndividual(constant); - final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); - node.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, iri)); - return node; - } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java new file mode 100644 index 0000000..9b0bc69 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java @@ -0,0 +1,33 @@ +package cz.cvut.kbss.jsonld.serialization.serializer.context; + +import cz.cvut.kbss.jsonld.ConfigParam; +import cz.cvut.kbss.jsonld.Configuration; +import cz.cvut.kbss.jsonld.common.BeanClassProcessor; +import cz.cvut.kbss.jsonld.common.EnumUtil; +import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; +import cz.cvut.kbss.jsonld.serialization.model.JsonNode; +import cz.cvut.kbss.jsonld.serialization.serializer.compact.IndividualSerializer; +import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; + +public class ContextBuildingIndividualSerializer extends IndividualSerializer { + + private boolean serializeUsingExtendedDefinition; + + @Override + public JsonNode serialize(Object value, SerializationContext ctx) { + if (serializeUsingExtendedDefinition) { + if (BeanClassProcessor.isIdentifierType(value.getClass())) { + return JsonNodeFactory.createStringLiteralNode(ctx.getTerm(), value.toString()); + } else { + return JsonNodeFactory.createStringLiteralNode(ctx.getTerm(), + EnumUtil.resolveMappedIndividual((Enum) value)); + } + } + return super.serialize(value, ctx); + } + + @Override + public void configure(Configuration config) { + this.serializeUsingExtendedDefinition = config.is(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION); + } +} diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java index d10815e..a9c0af2 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java @@ -1,12 +1,20 @@ package cz.cvut.kbss.jsonld.serialization.serializer.context; +import cz.cvut.kbss.jsonld.ConfigParam; +import cz.cvut.kbss.jsonld.Configuration; +import cz.cvut.kbss.jsonld.JsonLd; +import cz.cvut.kbss.jsonld.common.EnumUtil; +import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; +import cz.cvut.kbss.jsonld.serialization.serializer.SerializerUtils; import cz.cvut.kbss.jsonld.serialization.serializer.compact.ObjectPropertyValueSerializer; import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser; import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; public class ContextBuildingObjectPropertyValueSerializer extends ObjectPropertyValueSerializer { + private boolean serializeUsingExtendedDefinition; + public ContextBuildingObjectPropertyValueSerializer(ObjectGraphTraverser graphTraverser) { super(graphTraverser); } @@ -14,8 +22,23 @@ public ContextBuildingObjectPropertyValueSerializer(ObjectGraphTraverser graphTr @Override public JsonNode serialize(Object value, SerializationContext ctx) { if (ctx.getTerm() != null) { - ctx.registerTermMapping(ctx.getFieldName(), ctx.getTerm()); + registerTermDefinition(ctx); } return super.serialize(value, ctx); } + + private void registerTermDefinition(SerializationContext ctx) { + if (serializeUsingExtendedDefinition) { + ctx.registerTermMapping(ctx.getFieldName(), + SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(), + JsonLd.ID)); + } else { + ctx.registerTermMapping(ctx.getFieldName(), ctx.getTerm()); + } + } + + @Override + public void configure(Configuration config) { + this.serializeUsingExtendedDefinition = config.is(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION); + } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/InstanceVisitor.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/InstanceVisitor.java index 84a3789..5fc7087 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/InstanceVisitor.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/InstanceVisitor.java @@ -19,6 +19,14 @@ public interface InstanceVisitor { + /** + * Visits an object that represents an individual, without any additional attributes. + * + * This can be an identifier-based attribute value (e.g., URI), or an enum constant mapped to an individual. + * @param ctx Current serialization context + */ + void visitIndividual(SerializationContext ctx); + /** * Visits the instance represented by the specified context. *

diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java index 9291fdc..48dc36f 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java @@ -14,7 +14,6 @@ import cz.cvut.kbss.jsonld.common.BeanAnnotationProcessor; import cz.cvut.kbss.jsonld.common.BeanClassProcessor; -import cz.cvut.kbss.jsonld.common.EnumUtil; import cz.cvut.kbss.jsonld.common.IdentifierUtil; import cz.cvut.kbss.jsonld.exception.MissingIdentifierException; @@ -87,9 +86,13 @@ void traverseSingular(SerializationContext ctx) { if (!shouldTraverse) { return; } + if (isIndividual(ctx)) { + visitor.visitIndividual(ctx); + return; + } openInstance(ctx); visitIdentifier(ctx); - if (shouldTraverseObject(ctx, firstEncounter)) { + if (firstEncounter) { visitTypes(ctx); serializeFields(ctx); serializePropertiesField(ctx); @@ -97,9 +100,8 @@ void traverseSingular(SerializationContext ctx) { closeInstance(ctx); } - private boolean shouldTraverseObject(SerializationContext ctx, boolean firstEncounter) { - return firstEncounter && !BeanClassProcessor.isIdentifierType(ctx.getValue().getClass()) && - !ctx.getValue().getClass().isEnum(); + private static boolean isIndividual(SerializationContext ctx) { + return BeanClassProcessor.isIdentifierType(ctx.getValue().getClass()) || ctx.getValue().getClass().isEnum(); } private void serializeFields(SerializationContext ctx) { @@ -185,18 +187,10 @@ public void visitIdentifier(SerializationContext ctx) { final Class idCls = identifier.getClass(); final String id; final SerializationContext idContext; - if (BeanClassProcessor.isIdentifierType(idCls)) { - id = identifier.toString(); - idContext = serializationContextFactory.createForIdentifier(null, id, ctx); - } else if (idCls.isEnum()) { - id = EnumUtil.resolveMappedIndividual((Enum) identifier); - idContext = serializationContextFactory.createForIdentifier(null, id, ctx); - } else { - id = resolveIdentifier(identifier); - idContext = serializationContextFactory.createForIdentifier( - BeanAnnotationProcessor.getIdentifierField(idCls).orElse(null), id, ctx); - knownInstances.put(identifier, id); - } + id = resolveIdentifier(identifier); + idContext = serializationContextFactory.createForIdentifier( + BeanAnnotationProcessor.getIdentifierField(idCls).orElse(null), id, ctx); + knownInstances.put(identifier, id); visitor.visitIdentifier(idContext); } diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java index a5af90d..ae5e325 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java @@ -18,7 +18,6 @@ import cz.cvut.kbss.jsonld.environment.Vocabulary; import cz.cvut.kbss.jsonld.environment.model.*; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; -import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.eclipse.rdf4j.model.util.Models; @@ -327,15 +326,19 @@ void serializationSerializesIndividualsAsStringWithExpandedTermDefinitionInConte assertInstanceOf(Map.class, json.get(JsonLd.CONTEXT)); final Map context = (Map) json.get(JsonLd.CONTEXT); assertThat(context, hasKey("propertyType")); - final ObjectNode termDef = new ObjectNode("propertyType"); - termDef.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, Vocabulary.HAS_PROPERTY_TYPE)); - termDef.addItem(JsonNodeFactory.createStringLiteralNode(JsonLd.TYPE, JsonLd.ID)); - assertEquals(termDef, context.get("propertyType")); + assertInstanceOf(Map.class, context.get("propertyType")); + final Map termDef = (Map) context.get("propertyType"); + assertThat(termDef, hasKey(JsonLd.ID)); + assertEquals(termDef.get(JsonLd.ID), Vocabulary.HAS_PROPERTY_TYPE); + assertThat(termDef, hasKey(JsonLd.TYPE)); + assertEquals(termDef.get(JsonLd.TYPE), JsonLd.ID); assertThat(context, hasKey("pluralPropertyType")); - final ObjectNode pluralTermDef = new ObjectNode("pluralPropertyType"); - pluralTermDef.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, Vocabulary.HAS_PLURAL_PROPERTY_TYPE)); - pluralTermDef.addItem(JsonNodeFactory.createStringLiteralNode(JsonLd.TYPE, JsonLd.ID)); - assertEquals(pluralTermDef, context.get("pluralPropertyType")); + assertInstanceOf(Map.class, context.get("propertyType")); + final Map pluralTermDef = (Map) context.get("pluralPropertyType"); + assertThat(pluralTermDef, hasKey(JsonLd.ID)); + assertEquals(pluralTermDef.get(JsonLd.ID), Vocabulary.HAS_PLURAL_PROPERTY_TYPE); + assertThat(pluralTermDef, hasKey(JsonLd.TYPE)); + assertEquals(pluralTermDef.get(JsonLd.TYPE), JsonLd.ID); assertThat(json, hasKey("propertyType")); assertEquals(OWL.DATATYPE_PROPERTY, json.get("propertyType")); assertThat(json, hasKey("pluralPropertyType")); @@ -355,11 +358,10 @@ void serializationSerializesPlainIdentifierAsStringWithExpandedTermDefinitionInC assertInstanceOf(Map.class, json.get(JsonLd.CONTEXT)); final Map context = (Map) json.get(JsonLd.CONTEXT); assertThat(context, hasKey("country")); - final ObjectNode termDef = new ObjectNode("country"); - termDef.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, Vocabulary.ORIGIN)); - termDef.addItem(JsonNodeFactory.createStringLiteralNode(JsonLd.TYPE, JsonLd.ID)); - assertThat(context, hasKey("country")); - assertEquals(termDef, context.get("country")); + assertInstanceOf(Map.class, context.get("country")); + final Map termDef = (Map) context.get("country"); + assertEquals(Vocabulary.ORIGIN, termDef.get(JsonLd.ID)); + assertEquals(JsonLd.ID, termDef.get(JsonLd.TYPE)); assertEquals(instance.getCountry().toString(), json.get("country")); } } \ No newline at end of file diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializerTest.java new file mode 100644 index 0000000..ed5d954 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializerTest.java @@ -0,0 +1,69 @@ +package cz.cvut.kbss.jsonld.serialization.serializer.compact; + +import cz.cvut.kbss.jopa.model.annotations.Individual; +import cz.cvut.kbss.jopa.vocabulary.OWL; +import cz.cvut.kbss.jsonld.JsonLd; +import cz.cvut.kbss.jsonld.environment.Generator; +import cz.cvut.kbss.jsonld.environment.Vocabulary; +import cz.cvut.kbss.jsonld.environment.model.OwlPropertyType; +import cz.cvut.kbss.jsonld.exception.InvalidEnumMappingException; +import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; +import cz.cvut.kbss.jsonld.serialization.context.DummyJsonLdContext; +import cz.cvut.kbss.jsonld.serialization.model.JsonNode; +import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; +import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; +import org.junit.jupiter.api.Test; + +import java.net.URI; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.jupiter.api.Assertions.*; + +class IndividualSerializerTest { + + private final IndividualSerializer sut = new IndividualSerializer(); + + @Test + void serializeReturnsObjectNodeWithIdForSpecifiedIndividual() { + final URI individual = Generator.generateUri(); + final SerializationContext ctx = + new SerializationContext<>(Vocabulary.ORIGIN, individual, DummyJsonLdContext.INSTANCE); + + final JsonNode result = sut.serialize(individual, ctx); + assertInstanceOf(ObjectNode.class, result); + final ObjectNode objectNode = (ObjectNode) result; + assertEquals(1, objectNode.getItems().size()); + assertThat(objectNode.getItems(), + hasItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, individual.toString()))); + } + + @Test + void serializeReturnsObjectNodeWithIdForSpecifiedEnumConstantMappedToIndividual() { + final OwlPropertyType instance = OwlPropertyType.OBJECT_PROPERTY; + final SerializationContext ctx = + new SerializationContext<>(Vocabulary.HAS_PROPERTY_TYPE, instance, DummyJsonLdContext.INSTANCE); + + final JsonNode result = sut.serialize(instance, ctx); + assertInstanceOf(ObjectNode.class, result); + final ObjectNode objectNode = (ObjectNode) result; + assertEquals(1, objectNode.getItems().size()); + assertThat(objectNode.getItems(), hasItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, OWL.OBJECT_PROPERTY))); + } + + @Test + void serializeThrowsInvalidEnumMappingExceptionForEnumConstantWithoutMatchingIndividualMapping() { + final InvalidEnum instance = InvalidEnum.OBJECT_PROPERTY; + final SerializationContext ctx = + new SerializationContext<>(Vocabulary.HAS_PROPERTY_TYPE, instance, DummyJsonLdContext.INSTANCE); + + assertThrows(InvalidEnumMappingException.class, () -> sut.serialize(instance, ctx)); + } + + public enum InvalidEnum { + @Individual(iri = OWL.DATATYPE_PROPERTY) + DATATYPE_PROPERTY, + // Missing individual mapping here + OBJECT_PROPERTY + } +} \ No newline at end of file diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializerTest.java index 5fbd695..53e1208 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializerTest.java @@ -1,17 +1,10 @@ package cz.cvut.kbss.jsonld.serialization.serializer.compact; -import cz.cvut.kbss.jopa.model.annotations.Individual; -import cz.cvut.kbss.jopa.vocabulary.OWL; -import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.environment.Generator; import cz.cvut.kbss.jsonld.environment.Vocabulary; import cz.cvut.kbss.jsonld.environment.model.Employee; -import cz.cvut.kbss.jsonld.environment.model.OwlPropertyType; -import cz.cvut.kbss.jsonld.exception.InvalidEnumMappingException; -import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; import cz.cvut.kbss.jsonld.serialization.context.DummyJsonLdContext; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; -import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser; import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; import org.junit.jupiter.api.Test; @@ -20,9 +13,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) @@ -35,7 +26,7 @@ class ObjectPropertyValueSerializerTest { private ObjectPropertyValueSerializer sut; @Test - void serializeInvokesGraphTraverserForSpecifiedObjectByDefault() { + void serializeInvokesGraphTraverserForSpecifiedObject() { final Employee instance = Generator.generateEmployee(); final SerializationContext ctx = new SerializationContext<>(Vocabulary.HAS_MEMBER, instance, DummyJsonLdContext.INSTANCE); @@ -43,33 +34,4 @@ void serializeInvokesGraphTraverserForSpecifiedObjectByDefault() { assertNull(result); verify(graphTraverser).traverse(ctx); } - - @Test - void serializeReturnsObjectNodeWithIdForSpecifiedEnumConstantMappedToIndividual() { - final OwlPropertyType instance = OwlPropertyType.OBJECT_PROPERTY; - final SerializationContext ctx = - new SerializationContext<>(Vocabulary.HAS_PROPERTY_TYPE, instance, DummyJsonLdContext.INSTANCE); - - final JsonNode result = sut.serialize(instance, ctx); - assertInstanceOf(ObjectNode.class, result); - final ObjectNode objectNode = (ObjectNode) result; - assertEquals(1, objectNode.getItems().size()); - assertThat(objectNode.getItems(), hasItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, OWL.OBJECT_PROPERTY))); - } - - @Test - void serializeThrowsInvalidEnumMappingExceptionForEnumConstantWithoutMatchingIndividualMapping() { - final InvalidEnum instance = InvalidEnum.OBJECT_PROPERTY; - final SerializationContext ctx = - new SerializationContext<>(Vocabulary.HAS_PROPERTY_TYPE, instance, DummyJsonLdContext.INSTANCE); - - assertThrows(InvalidEnumMappingException.class, () -> sut.serialize(instance, ctx)); - } - - public enum InvalidEnum { - @Individual(iri = OWL.DATATYPE_PROPERTY) - DATATYPE_PROPERTY, - // Missing individual mapping here - OBJECT_PROPERTY - } } \ No newline at end of file diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java index e48a138..7e8391e 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java @@ -1,10 +1,14 @@ package cz.cvut.kbss.jsonld.serialization.serializer.context; +import cz.cvut.kbss.jsonld.ConfigParam; +import cz.cvut.kbss.jsonld.Configuration; +import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.environment.Generator; import cz.cvut.kbss.jsonld.environment.Vocabulary; import cz.cvut.kbss.jsonld.environment.model.Employee; import cz.cvut.kbss.jsonld.environment.model.Organization; import cz.cvut.kbss.jsonld.serialization.context.JsonLdContext; +import cz.cvut.kbss.jsonld.serialization.serializer.SerializerUtils; import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser; import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; import org.junit.jupiter.api.Test; @@ -13,7 +17,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -36,4 +39,21 @@ void serializeRegistersTermIriMappingInJsonLdContext() throws Exception { sut.serialize(value, serializationCtx); verify(ctx).registerTermMapping(Employee.getEmployerField().getName(), Vocabulary.IS_MEMBER_OF); } + + @Test + void serializeRegistersExtendedTermDefinitionWithIdAndTypeInJsonLdContextWhenConfiguredToUseExtendedDefinition() throws Exception { + final Configuration config = new Configuration(); + config.set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + sut.configure(config); + final JsonLdContext ctx = mock(JsonLdContext.class); + final Organization value = Generator.generateOrganization(); + final SerializationContext serializationCtx = + new SerializationContext<>(Vocabulary.IS_MEMBER_OF, Employee.getEmployerField(), value, ctx); + + sut.serialize(value, serializationCtx); + verify(ctx).registerTermMapping(Employee.getEmployerField().getName(), + SerializerUtils.createTypedTermDefinition(Employee.getEmployerField().getName(), + Vocabulary.IS_MEMBER_OF, + JsonLd.ID)); + } } \ No newline at end of file diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java index bdfb4f0..9c18047 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverserTest.java @@ -16,7 +16,6 @@ import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; import cz.cvut.kbss.jopa.model.annotations.Types; -import cz.cvut.kbss.jopa.vocabulary.OWL; import cz.cvut.kbss.jopa.vocabulary.RDFS; import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.annotation.JsonLdAttributeOrder; @@ -30,7 +29,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -225,18 +223,17 @@ void traverseInvokesVisitIdentifierWithInstanceIdentifier() throws Exception { } @Test - void traverseInvokesVisitWhenInstanceIsPlainIdentifierPropertyValue() throws Exception { + void traverseInvokesVisitIndividualWhenInstanceIsPlainIdentifierPropertyValue() throws Exception { final EmployeeWithUriEmployer employee = new EmployeeWithUriEmployer(); employee.setUri(Generator.generateUri()); employee.employer = Generator.generateUri(); - traverser.traverse(ctx(Vocabulary.IS_MEMBER_OF, EmployeeWithUriEmployer.class.getDeclaredField("employer"), - employee.employer)); - final InOrder inOrder = inOrder(visitor); - inOrder.verify(visitor).openObject( - ctx(Vocabulary.IS_MEMBER_OF, EmployeeWithUriEmployer.class.getDeclaredField("employer"), - employee.employer)); - inOrder.verify(visitor).visitIdentifier(ctx(JsonLd.ID, null, employee.employer.toString())); + final SerializationContext ctx = ctx(Vocabulary.IS_MEMBER_OF, EmployeeWithUriEmployer.class.getDeclaredField("employer"), + employee.employer); + traverser.traverse(ctx); + verify(visitor).visitIndividual(ctx); + verify(visitor, never()).visitAttribute(any()); + verify(visitor, never()).visitTypes(any()); } @Test @@ -336,15 +333,11 @@ void traverseDoesNotOpenObjectWhenVisitObjectReturnedFalse() { } @Test - void traverseSingularEnumConstantOpensObjectAndAddsOnlyIdentifierToIt() { + void traverseSingularEnumConstantVisitsIndividual() { final SerializationContext ctx = new SerializationContext<>(OwlPropertyType.OBJECT_PROPERTY, DummyJsonLdContext.INSTANCE); traverser.traverse(ctx); - verify(visitor).openObject(ctx); - final ArgumentCaptor> captor = ArgumentCaptor.forClass(SerializationContext.class); - verify(visitor).visitIdentifier(captor.capture()); - assertEquals(OWL.OBJECT_PROPERTY, captor.getValue().getValue()); - assertEquals(JsonLd.ID, captor.getValue().getTerm()); + verify(visitor).visitIndividual(ctx); verify(visitor, never()).visitAttribute(any()); verify(visitor, never()).visitTypes(any()); } From 56ee07d9a94b803623741f12f435eb0e4ff634c4 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 31 Mar 2023 10:41:48 +0200 Subject: [PATCH 09/15] [Enhancement #54] Minor code cleanup, add some tests. --- .../compact/IndividualSerializer.java | 21 ++++---- .../ObjectPropertyValueSerializer.java | 4 -- .../ContextBuildingIndividualSerializer.java | 1 + .../traversal/ObjectGraphTraverser.java | 8 ++- ...ntextBuildingIndividualSerializerTest.java | 52 +++++++++++++++++++ 5 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializerTest.java diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java index 05dccf6..669a80a 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/IndividualSerializer.java @@ -21,22 +21,21 @@ public class IndividualSerializer implements ValueSerializer { public JsonNode serialize(Object value, SerializationContext ctx) { assert BeanClassProcessor.isIdentifierType(value.getClass()) || value.getClass().isEnum(); if (BeanClassProcessor.isIdentifierType(value.getClass())) { - final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); - node.addItem(JsonNodeFactory.createObjectIdNode(idAttribute(ctx), value)); - return node; + return serializeValue(value, ctx); } else { - return serializeEnumConstant((Enum) value, ctx); + assert value instanceof Enum; + final String iri = EnumUtil.resolveMappedIndividual((Enum) value); + return serialize(iri, ctx); } } - private String idAttribute(SerializationContext ctx) { - return ctx.getJsonLdContext().getMappedTerm(JsonLd.ID).orElse(JsonLd.ID); - } - - protected JsonNode serializeEnumConstant(Enum constant, SerializationContext ctx) { - final String iri = EnumUtil.resolveMappedIndividual(constant); + private JsonNode serializeValue(Object value, SerializationContext ctx) { final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); - node.addItem(JsonNodeFactory.createObjectIdNode(idAttribute(ctx), iri)); + node.addItem(JsonNodeFactory.createObjectIdNode(idAttribute(ctx), value)); return node; } + + private String idAttribute(SerializationContext ctx) { + return ctx.getJsonLdContext().getMappedTerm(JsonLd.ID).orElse(JsonLd.ID); + } } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java index 0db24c4..6ea3f7e 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/ObjectPropertyValueSerializer.java @@ -12,11 +12,7 @@ */ package cz.cvut.kbss.jsonld.serialization.serializer.compact; -import cz.cvut.kbss.jsonld.JsonLd; -import cz.cvut.kbss.jsonld.common.EnumUtil; -import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; -import cz.cvut.kbss.jsonld.serialization.model.ObjectNode; import cz.cvut.kbss.jsonld.serialization.serializer.ValueSerializer; import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser; import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java index 9b0bc69..33848ec 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializer.java @@ -15,6 +15,7 @@ public class ContextBuildingIndividualSerializer extends IndividualSerializer { @Override public JsonNode serialize(Object value, SerializationContext ctx) { + // Assume term has been already registered in context if (serializeUsingExtendedDefinition) { if (BeanClassProcessor.isIdentifierType(value.getClass())) { return JsonNodeFactory.createStringLiteralNode(ctx.getTerm(), value.toString()); diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java index 48dc36f..7e22f98 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java @@ -81,15 +81,15 @@ void traverseSingular(SerializationContext ctx) { if (ctx.getValue() == null) { return; } - final boolean firstEncounter = !knownInstances.containsKey(ctx.getValue()); final boolean shouldTraverse = visitInstance(ctx); if (!shouldTraverse) { return; } if (isIndividual(ctx)) { - visitor.visitIndividual(ctx); + visitIndividual(ctx); return; } + final boolean firstEncounter = !knownInstances.containsKey(ctx.getValue()); openInstance(ctx); visitIdentifier(ctx); if (firstEncounter) { @@ -161,6 +161,10 @@ public boolean visitInstance(SerializationContext ctx) { return visitor.visitObject(ctx); } + public void visitIndividual(SerializationContext ctx) { + visitor.visitIndividual(ctx); + } + public void openInstance(SerializationContext ctx) { if (!BeanClassProcessor.isIdentifierType(ctx.getValue().getClass())) { final String identifier = resolveIdentifier(ctx.getValue()); diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializerTest.java new file mode 100644 index 0000000..0fd4555 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingIndividualSerializerTest.java @@ -0,0 +1,52 @@ +package cz.cvut.kbss.jsonld.serialization.serializer.context; + +import cz.cvut.kbss.jopa.vocabulary.OWL; +import cz.cvut.kbss.jsonld.ConfigParam; +import cz.cvut.kbss.jsonld.Configuration; +import cz.cvut.kbss.jsonld.environment.Generator; +import cz.cvut.kbss.jsonld.environment.Vocabulary; +import cz.cvut.kbss.jsonld.environment.model.OwlPropertyType; +import cz.cvut.kbss.jsonld.serialization.context.DummyJsonLdContext; +import cz.cvut.kbss.jsonld.serialization.model.JsonNode; +import cz.cvut.kbss.jsonld.serialization.model.StringLiteralNode; +import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; +import org.junit.jupiter.api.Test; + +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.*; + +class ContextBuildingIndividualSerializerTest { + + private final ContextBuildingIndividualSerializer sut = new ContextBuildingIndividualSerializer(); + + @Test + void serializeSerializesUriValueAsStringWhenSerializationWithExtendedTermDefinitionInContextIsEnabled() { + final URI individual = Generator.generateUri(); + final SerializationContext ctx = + new SerializationContext<>(Vocabulary.ORIGIN, individual, DummyJsonLdContext.INSTANCE); + final Configuration config = new Configuration(); + config.set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + + sut.configure(config); + final JsonNode result = sut.serialize(individual, ctx); + assertInstanceOf(StringLiteralNode.class, result); + final StringLiteralNode node = (StringLiteralNode) result; + assertEquals(individual.toString(), node.getValue()); + } + + @Test + void serializeSerializesEnumValueMappedToIndividualAsStringWhenSerializationWithExtendedTermDefinitionInContextIsEnabled() { + final OwlPropertyType value = OwlPropertyType.OBJECT_PROPERTY; + final SerializationContext ctx = + new SerializationContext<>(Vocabulary.HAS_PROPERTY_TYPE, value, DummyJsonLdContext.INSTANCE); + final Configuration config = new Configuration(); + config.set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + + sut.configure(config); + final JsonNode result = sut.serialize(value, ctx); + assertInstanceOf(StringLiteralNode.class, result); + final StringLiteralNode node = (StringLiteralNode) result; + assertEquals(OWL.OBJECT_PROPERTY, node.getValue()); + } +} \ No newline at end of file From d38ddd31092dedfb235eaa0d1e1b5ddd2df2ff25 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 31 Mar 2023 12:57:44 +0200 Subject: [PATCH 10/15] [Ref] Simplify creation of JSON nodes. Remove most of the checks for attribute name - it will be handled by the JSON node implementation itself so that it is done just in one place. --- .../cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java | 8 ++------ .../serializer/compact/DefaultValueSerializer.java | 3 +-- .../serializer/compact/MultilingualStringSerializer.java | 5 ++--- .../ContextBuildingMultilingualStringSerializer.java | 2 +- .../ContextBuildingObjectPropertyValueSerializer.java | 2 -- ...ContextBuildingPluralMultilingualStringSerializer.java | 2 +- 6 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java index 4648069..d719a7c 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonLdTreeBuilder.java @@ -75,8 +75,7 @@ public boolean visitObject(SerializationContext ctx) { @Override public void openObject(SerializationContext ctx) { - final ObjectNode newCurrent = ctx.getTerm() != null ? JsonNodeFactory.createObjectNode(ctx.getTerm()) : - JsonNodeFactory.createObjectNode(); + final ObjectNode newCurrent = JsonNodeFactory.createObjectNode(ctx.getTerm()); openNewNode(newCurrent); // Prepare to create new JSON-LD context when an object is open ctx.setJsonLdContext(jsonLdContextFactory.createJsonLdContext(ctx.getJsonLdContext())); @@ -132,10 +131,7 @@ public void visitAttribute(SerializationContext ctx) { @Override public void openCollection(SerializationContext> ctx) { - final CollectionNode newCurrent = - ctx.getTerm() != null ? JsonNodeFactory.createCollectionNode(ctx.getTerm(), - ctx.getValue()) : - JsonNodeFactory.createCollectionNode(ctx.getValue()); + final CollectionNode newCurrent =JsonNodeFactory.createCollectionNode(ctx.getTerm(), ctx.getValue()); openNewNode(newCurrent); } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/DefaultValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/DefaultValueSerializer.java index 8957cb6..825d4e0 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/DefaultValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/DefaultValueSerializer.java @@ -61,8 +61,7 @@ public JsonNode serialize(Object value, SerializationContext ctx) { } private static JsonNode serializeReference(String attId, Object value) { - final ObjectNode node = - attId != null ? JsonNodeFactory.createObjectNode(attId) : JsonNodeFactory.createObjectNode(); + final ObjectNode node = JsonNodeFactory.createObjectNode(attId); node.addItem(JsonNodeFactory.createObjectIdNode(JsonLd.ID, value)); return node; } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/MultilingualStringSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/MultilingualStringSerializer.java index 8d883d3..0c645d7 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/MultilingualStringSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/MultilingualStringSerializer.java @@ -34,14 +34,13 @@ public JsonNode serialize(MultilingualString value, SerializationContext entry = value.getValue().entrySet().iterator().next(); return createNode(ctx.getTerm(), entry.getValue(), entry.getKey()); } - final SetNode collectionNode = ctx.getTerm() != null ? JsonNodeFactory.createCollectionNodeFromArray(ctx.getTerm()) : JsonNodeFactory.createCollectionNodeFromArray(); + final SetNode collectionNode = JsonNodeFactory.createCollectionNodeFromArray(ctx.getTerm()); addTranslationsToCollectionNode(value, collectionNode); return collectionNode; } private static JsonNode createNode(String attName, String value, String language) { - final ObjectNode node = - attName != null ? JsonNodeFactory.createObjectNode(attName) : JsonNodeFactory.createObjectNode(); + final ObjectNode node = JsonNodeFactory.createObjectNode(attName); node.addItem(JsonNodeFactory.createLiteralNode(JsonLd.LANGUAGE, language != null ? language : JsonLd.NONE)); node.addItem(JsonNodeFactory.createLiteralNode(JsonLd.VALUE, value)); return node; diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingMultilingualStringSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingMultilingualStringSerializer.java index df493d2..2c3f4c9 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingMultilingualStringSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingMultilingualStringSerializer.java @@ -17,7 +17,7 @@ public ObjectNode serialize(MultilingualString value, SerializationContext node.addItem(JsonNodeFactory.createLiteralNode(lang != null ? lang : JsonLd.NONE, text))); return node; } diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java index a9c0af2..9e45bc4 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java @@ -3,8 +3,6 @@ import cz.cvut.kbss.jsonld.ConfigParam; import cz.cvut.kbss.jsonld.Configuration; import cz.cvut.kbss.jsonld.JsonLd; -import cz.cvut.kbss.jsonld.common.EnumUtil; -import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; import cz.cvut.kbss.jsonld.serialization.serializer.SerializerUtils; import cz.cvut.kbss.jsonld.serialization.serializer.compact.ObjectPropertyValueSerializer; diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingPluralMultilingualStringSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingPluralMultilingualStringSerializer.java index a8e41c6..f2cf584 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingPluralMultilingualStringSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingPluralMultilingualStringSerializer.java @@ -23,7 +23,7 @@ public ObjectNode serialize(Collection value, allValues.putIfAbsent(lang, new LinkedHashSet<>()); allValues.get(lang).add(text); })); - final ObjectNode node = ctx.getField() != null ? JsonNodeFactory.createObjectNode(ctx.getTerm()) : JsonNodeFactory.createObjectNode(); + final ObjectNode node = JsonNodeFactory.createObjectNode(ctx.getTerm()); allValues.forEach((lang, texts) -> { final String langKey = lang != null ? lang : JsonLd.NONE; if (texts.size() == 1) { From 76982fb8e58ddeec65a3a818f23fb9dd673ec256 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 31 Mar 2023 13:02:11 +0200 Subject: [PATCH 11/15] [Ref] Simplify JsonNodeFactory, remove unused methods. --- .../jsonld/serialization/JsonNodeFactory.java | 35 +++---------------- .../serialization/JsonNodeFactoryTest.java | 26 +------------- .../ObjectGraphValueSerializersTest.java | 4 +-- 3 files changed, 7 insertions(+), 58 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactory.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactory.java index 8862a70..18b6131 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactory.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactory.java @@ -69,19 +69,6 @@ public static StringLiteralNode createStringLiteralNode(String name, String valu return name != null ? new StringLiteralNode(name, value) : new StringLiteralNode(value); } - /** - * Creates collection node for the specified collection. - *

- * The node is without name, so it cannot be used as attribute. - * - * @param value The collection. It is used only to determine the type of the target node, no values are added to the - * result - * @return An empty collection node - */ - public static CollectionNode createCollectionNode(Collection value) { - return createCollectionNode(null, value); - } - /** * Creates collection node with the specified name, for the specified collection. * @@ -92,16 +79,14 @@ public static CollectionNode createCollectionNode(Collection value) { */ public static CollectionNode createCollectionNode(String name, Collection value) { final CollectionType type = determineCollectionType(value); - CollectionNode n = null; switch (type) { case LIST: - n = name != null ? new ListNode(name) : new ListNode(); - break; + return new ListNode(name); case SET: - n = name != null ? createSetNode(name) : createSetNode(); - break; + return createSetNode(name); + default: + throw new IllegalArgumentException("Unsupported collection type " + type); } - return n; } private static CollectionType determineCollectionType(Collection collection) { @@ -114,18 +99,10 @@ private static CollectionType determineCollectionType(Collection collection) } } - public static SetNode createSetNode() { - return new SetNode(); - } - public static SetNode createSetNode(String name) { return new SetNode(name); } - public static SetNode createCollectionNodeFromArray() { - return createSetNode(); - } - public static SetNode createCollectionNodeFromArray(String name) { return createSetNode(name); } @@ -138,10 +115,6 @@ public static ObjectNode createObjectNode(String name) { return new ObjectNode(name); } - public static ObjectIdNode createObjectIdNode(Object id) { - return new ObjectIdNode(id.toString()); - } - public static ObjectIdNode createObjectIdNode(String name, Object id) { return new ObjectIdNode(name, id.toString()); } diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactoryTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactoryTest.java index b76ddc3..9aaf1fa 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactoryTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/JsonNodeFactoryTest.java @@ -16,7 +16,6 @@ import cz.cvut.kbss.jsonld.serialization.model.*; import org.junit.jupiter.api.Test; -import java.net.URI; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -30,14 +29,6 @@ class JsonNodeFactoryTest { private static final String NAME = Generator.generateUri().toString(); - @Test - void createCollectionCreatesListNodeFromListWithoutName() { - final List list = new ArrayList<>(); - final CollectionNode node = JsonNodeFactory.createCollectionNode(list); - assertThat(node, instanceOf(ListNode.class)); - assertTrue(node.isValueNode()); - } - @Test void createCollectionCreatesListNodeFromListWithName() { final List list = new ArrayList<>(); @@ -50,7 +41,7 @@ void createCollectionCreatesListNodeFromListWithName() { @Test void createCollectionCreatesSetNodeFromSetWithoutName() { final Set set = new HashSet<>(); - final CollectionNode node = JsonNodeFactory.createCollectionNode(set); + final CollectionNode node = JsonNodeFactory.createCollectionNode(null, set); assertThat(node, instanceOf(SetNode.class)); assertTrue(node.isValueNode()); } @@ -72,14 +63,6 @@ void createCollectionFromArrayCreatesSetNodeWithName() { assertFalse(node.isValueNode()); } - @Test - void createCollectionFromArrayCreatesSetNodeWithoutName() { - final CollectionNode node = JsonNodeFactory.createCollectionNodeFromArray(); - assertThat(node, instanceOf(SetNode.class)); - assertNull(node.getName()); - assertTrue(node.isValueNode()); - } - @Test void createLiteralNodeCreatesBooleanNodeFromBooleanValueWithName() { final LiteralNode node = JsonNodeFactory.createLiteralNode(NAME, false); @@ -133,11 +116,4 @@ void createLiteralNodeCreatesStringNodeFromStringWithoutName() { assertTrue(node.isValueNode()); assertEquals(value, node.getValue()); } - - @Test - void createObjectIdNodeWithoutAttributeCreatesNamelessObjectIdNode() { - final URI uri = Generator.generateUri(); - final ObjectIdNode node = JsonNodeFactory.createObjectIdNode(uri); - assertNull(node.getName()); - } } diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializersTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializersTest.java index 034d60c..774347b 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializersTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/ObjectGraphValueSerializersTest.java @@ -73,7 +73,7 @@ void getSerializerReturnsEmptyOptionalWhenFieldIsNotObjectPropertyAndNoCustomSer @Test void getSerializerReturnsCustomSerializerWhenItIsRegisteredInCommon() throws Exception { final ValueSerializer serializer = - ((value, ctx) -> JsonNodeFactory.createObjectIdNode(Generator.generateUri())); + ((value, ctx) -> JsonNodeFactory.createObjectIdNode(ctx.getTerm(), Generator.generateUri())); sut.registerSerializer(Organization.class, serializer); final SerializationContext ctx = new SerializationContext<>(Vocabulary.IS_MEMBER_OF, Employee.getEmployerField(), @@ -95,7 +95,7 @@ void getOrDefaultReturnsObjectPropertySerializerWhenProvidedFieldIsObjectPropert @Test void getOrDefaultReturnsCustomSerializerWhenItIsRegistered() throws Exception { final ValueSerializer serializer = - ((value, ctx) -> JsonNodeFactory.createObjectIdNode(Generator.generateUri())); + ((value, ctx) -> JsonNodeFactory.createObjectIdNode(ctx.getTerm(), Generator.generateUri())); sut.registerSerializer(Organization.class, serializer); final SerializationContext ctx = new SerializationContext<>(Vocabulary.IS_MEMBER_OF, Employee.getEmployerField(), From ebf773a50952aa4c42b7b47db907b298fb6058bc Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 31 Mar 2023 15:23:03 +0200 Subject: [PATCH 12/15] [Enhancement #54] Ensure extended term definition is correctly created for collection-valued object property attributes. --- .../jsonld/common/BeanClassProcessor.java | 12 +++++ ...BuildingObjectPropertyValueSerializer.java | 20 ++++++++- .../traversal/ObjectGraphTraverser.java | 6 +-- ...dingObjectPropertyValueSerializerTest.java | 44 +++++++++++++++++-- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java b/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java index c1a9a72..21f7610 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java +++ b/src/main/java/cz/cvut/kbss/jsonld/common/BeanClassProcessor.java @@ -244,6 +244,18 @@ public static void verifyPropertiesFieldType(Field field) { } } + /** + * Checks whether the specified class represents an individual reference and not a complex object. + * + * Individual references are identifiers or enum constants mapped to individuals. + * @param cls Class to check + * @return {@code true} when the type represents an individual, {@code false} otherwise + * @see #isIdentifierType(Class) + */ + public static boolean isIndividualType(Class cls) { + return isIdentifierType(cls) || cls.isEnum(); + } + /** * Checks whether the specified type is a valid identifier type. * diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java index 9e45bc4..0a76f7a 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializer.java @@ -3,12 +3,15 @@ import cz.cvut.kbss.jsonld.ConfigParam; import cz.cvut.kbss.jsonld.Configuration; import cz.cvut.kbss.jsonld.JsonLd; +import cz.cvut.kbss.jsonld.common.BeanClassProcessor; import cz.cvut.kbss.jsonld.serialization.model.JsonNode; import cz.cvut.kbss.jsonld.serialization.serializer.SerializerUtils; import cz.cvut.kbss.jsonld.serialization.serializer.compact.ObjectPropertyValueSerializer; import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser; import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext; +import java.util.Collection; + public class ContextBuildingObjectPropertyValueSerializer extends ObjectPropertyValueSerializer { private boolean serializeUsingExtendedDefinition; @@ -26,7 +29,7 @@ public JsonNode serialize(Object value, SerializationContext ctx) { } private void registerTermDefinition(SerializationContext ctx) { - if (serializeUsingExtendedDefinition) { + if (serializeUsingExtendedDefinition && isIndividual(ctx)) { ctx.registerTermMapping(ctx.getFieldName(), SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(), JsonLd.ID)); @@ -35,6 +38,21 @@ private void registerTermDefinition(SerializationContext ctx) { } } + private static boolean isIndividual(SerializationContext ctx) { + if (BeanClassProcessor.isIndividualType(ctx.getValue().getClass())) { + return true; + } + if (ctx.getValue() instanceof Collection) { + final Collection c = (Collection) ctx.getValue(); + for (Object elem : c) { + if (elem != null) { + return BeanClassProcessor.isIndividualType(elem.getClass()); + } + } + } + return false; + } + @Override public void configure(Configuration config) { this.serializeUsingExtendedDefinition = config.is(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION); diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java index 7e22f98..4dd1dcc 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/traversal/ObjectGraphTraverser.java @@ -85,7 +85,7 @@ void traverseSingular(SerializationContext ctx) { if (!shouldTraverse) { return; } - if (isIndividual(ctx)) { + if (BeanClassProcessor.isIndividualType(ctx.getValue().getClass())) { visitIndividual(ctx); return; } @@ -100,10 +100,6 @@ void traverseSingular(SerializationContext ctx) { closeInstance(ctx); } - private static boolean isIndividual(SerializationContext ctx) { - return BeanClassProcessor.isIdentifierType(ctx.getValue().getClass()) || ctx.getValue().getClass().isEnum(); - } - private void serializeFields(SerializationContext ctx) { final Object instance = ctx.getValue(); final List fieldsToSerialize = diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java index 7e8391e..649ec66 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/serializer/context/ContextBuildingObjectPropertyValueSerializerTest.java @@ -17,6 +17,11 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.net.URI; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -42,6 +47,23 @@ void serializeRegistersTermIriMappingInJsonLdContext() throws Exception { @Test void serializeRegistersExtendedTermDefinitionWithIdAndTypeInJsonLdContextWhenConfiguredToUseExtendedDefinition() throws Exception { + final Configuration config = new Configuration(); + config.set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + sut.configure(config); + final JsonLdContext ctx = mock(JsonLdContext.class); + final URI value = Generator.generateUri(); + final SerializationContext serializationCtx = + new SerializationContext<>(Vocabulary.ORIGIN, Organization.class.getDeclaredField("country"), value, + ctx); + + sut.serialize(value, serializationCtx); + verify(ctx).registerTermMapping("country", + SerializerUtils.createTypedTermDefinition("country", Vocabulary.ORIGIN, + JsonLd.ID)); + } + + @Test + void serializeRegistersTermIriMappingInJsonLdContextWhenConfiguredToUseExtendedDefinitionWhenValueIsComplex() throws Exception { final Configuration config = new Configuration(); config.set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); sut.configure(config); @@ -51,9 +73,23 @@ void serializeRegistersExtendedTermDefinitionWithIdAndTypeInJsonLdContextWhenCon new SerializationContext<>(Vocabulary.IS_MEMBER_OF, Employee.getEmployerField(), value, ctx); sut.serialize(value, serializationCtx); - verify(ctx).registerTermMapping(Employee.getEmployerField().getName(), - SerializerUtils.createTypedTermDefinition(Employee.getEmployerField().getName(), - Vocabulary.IS_MEMBER_OF, - JsonLd.ID)); + verify(ctx).registerTermMapping(Employee.getEmployerField().getName(), Vocabulary.IS_MEMBER_OF); + } + + @Test + void serializeRegistersTermIriMappingInJsonLdContextWhenConfiguredToUseExtendedDefinitionWhenValueIsCollectionOfComplexObjects() throws Exception { + final Configuration config = new Configuration(); + config.set(ConfigParam.SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION, Boolean.TRUE.toString()); + sut.configure(config); + final JsonLdContext ctx = mock(JsonLdContext.class); + final Set value = new HashSet<>(Arrays.asList(Generator.generateUri(), Generator.generateUri())); + final SerializationContext> serializationCtx = + new SerializationContext<>(Vocabulary.HAS_MEMBER, Organization.getEmployeesField(), value, ctx); + + sut.serialize(value, serializationCtx); + verify(ctx).registerTermMapping(Organization.getEmployeesField().getName(), + SerializerUtils.createTypedTermDefinition( + Organization.getEmployeesField().getName(), Vocabulary.HAS_MEMBER, + JsonLd.ID)); } } \ No newline at end of file From 0bc4f3cfcf08444a5d0b44e324b6f96fd8cdbdd2 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 31 Mar 2023 15:23:28 +0200 Subject: [PATCH 13/15] [Fix] Fix serialization of types with context when term is mapped in ancestor context. --- .../context/EmbeddedTermMappingHolder.java | 9 +++++++++ .../context/EmbeddedTermMappingHolderTest.java | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolder.java b/src/main/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolder.java index d119dfb..badf76a 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolder.java +++ b/src/main/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolder.java @@ -68,6 +68,15 @@ boolean hasTermMapping(String term, JsonNode mappedNode) { return mapping.containsKey(term) && mapping.get(term).equals(mappedNode); } + @Override + public Optional getMappedTerm(String iri) { + final Optional result = super.getMappedTerm(iri); + if (result.isPresent()) { + return result; + } + return parentContext.getMappedTerm(iri); + } + @Override boolean isEmpty() { return mapping.isEmpty(); diff --git a/src/test/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolderTest.java b/src/test/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolderTest.java index 6b21482..f3884ba 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolderTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/serialization/context/EmbeddedTermMappingHolderTest.java @@ -6,6 +6,8 @@ import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory; import org.junit.jupiter.api.Test; +import java.util.Optional; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.not; @@ -33,4 +35,14 @@ void registerTermMappingDoesNothingWhenParentContextAlreadyHasEquivalentMappingF assertThat(child.getMapping(), not(hasKey(term))); assertTrue(child.hasTermMapping(term)); } + + @Test + void getMappedTermReturnsMappedValueFromParentWhenItIsNotPresentInCurrentHolder() { + final EmbeddedTermMappingHolder child = new EmbeddedTermMappingHolder(sut); + final String term = "name"; + sut.registerTermMapping(term, JsonNodeFactory.createStringLiteralNode(term, RDFS.LABEL)); + final Optional result = child.getMappedTerm(RDFS.LABEL); + assertTrue(result.isPresent()); + assertEquals(term, result.get()); + } } \ No newline at end of file From 1428dc174d811e7664d5b4c63c0111f22eadd491 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 6 Apr 2023 20:40:11 +0200 Subject: [PATCH 14/15] [0.12.3] Bump version, update changelog. --- CHANGELOG.md | 5 +++++ pom.xml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f17a758..99978e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # JB4JSON-LD Changelog +## 0.12.3 - 2023-04-06 +- Support serializing individuals as string with an extended term definition in context (Enhancement #54). +- Fix serialization of types when parent context specifies term mapping. +- Remove unused JSON node creation methods. + ## 0.12.2 - 2023-03-30 - Fix an issue with context embedding (Bug #51). diff --git a/pom.xml b/pom.xml index 52dd372..7e6dfb3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ cz.cvut.kbss.jsonld jb4jsonld - 0.12.2 + 0.12.3 JB4JSON-LD Java Binding for JSON-LD allows serialization and deserialization of Java POJOs to/from JSON-LD. This is the core implementation, which has to be integrated with Jackson, Jersey etc. From 101b6b06a9a81402f3d9194544196a33b71d1c48 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 6 Apr 2023 20:46:29 +0200 Subject: [PATCH 15/15] [Doc] Update readme with info on serialization of individuals as strings. --- README.md | 52 ++++++++++--------- .../java/cz/cvut/kbss/jsonld/ConfigParam.java | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 1227c03..a4be3d0 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,25 @@ Java Binding for JSON-LD (JB4JSON-LD) is a simple library for serialization of Java objects into JSON-LD and vice versa. -Note that this is the core, abstract implementation. For actual usage, a binding like [JB4JSON-LD Jackson](https://github.com/kbss-cvut/jb4jsonld-jackson) +Note that this is the core, abstract implementation. For actual usage, a binding +like [JB4JSON-LD Jackson](https://github.com/kbss-cvut/jb4jsonld-jackson) has to be used. - ## Usage -JB4JSON-LD is based on annotations from [JOPA](https://github.com/kbss-cvut/jopa), which enable POJO attributes -to be mapped to ontological constructs (i.e. to object, data or annotation properties) and Java classes to ontological +JB4JSON-LD is based on annotations from [JOPA](https://github.com/kbss-cvut/jopa), which enable POJO attributes to be +mapped to ontological constructs (i.e. to object, data or annotation properties) and Java classes to ontological classes. -Use `@OWLDataProperty` to annotate data fields and `@OWLObjectProperty` to annotate fields referencing other mapped entities. -You can mark DTOs with `@NonEntity` to tell JOPA to ignore such classes completely (e.g., they will be ignored when AspectJ -is inserting JOPA-specific join points into entity classes). - -See [https://github.com/kbss-cvut/jopa-examples/tree/master/jsonld](https://github.com/kbss-cvut/jopa-examples/tree/master/jsonld) for -an executable example of JB4JSON-LD in action (together with Spring and Jackson). The [JB4JSON-LD Jackson](https://github.com/kbss-cvut/jb4jsonld-jackson) -repository also contains a bare-bones example of setting the library up with Jackson (two DTO classes and a short Main class). +Use `@OWLDataProperty` to annotate data fields and `@OWLObjectProperty` to annotate fields referencing other mapped +entities. You can mark DTOs with `@NonEntity` to tell JOPA to ignore such classes completely (e.g., they will be ignored +when AspectJ is inserting JOPA-specific join points into entity classes). +See [https://github.com/kbss-cvut/jopa-examples/tree/master/jsonld](https://github.com/kbss-cvut/jopa-examples/tree/master/jsonld) +for an executable example of JB4JSON-LD in action (together with Spring and Jackson). +The [JB4JSON-LD Jackson](https://github.com/kbss-cvut/jb4jsonld-jackson) +repository also contains a bare-bones example of setting the library up with Jackson (two DTO classes and a short Main +class). ## Example @@ -90,22 +91,24 @@ public class User { ## Configuration -| Parameter | Default value | Explanation | -|----------------------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `ignoreUnknownProperties` | `false` | Whether to ignore unknown properties when deserializing JSON-LD. Default behavior throws an exception. | -| `scanPackage` | `""` | Package in which the library should look for mapped classes. The scan is important for support for polymorphism in object deserialization. It is highly recommended to specify this value, otherwise the library will attempt to load and scan all classes on the classpath. | -| `requireId` | `false` | Whether to require an identifier when serializing an object. If set to `true` and no identifier is found (either there is no `@Id` field or its value is `null`), an exception will be thrown. By default a blank node identifier is generated if no id is present. | -| `assumeTargetType` | `false` | Whether to allow assuming target type in case the JSON-LD object does not contain types (`@type`). If set to `true`, the provided Java type (deserialization invocation argument, field type) will be used as target type. | -| `enableOptimisticTargetTypeResolution` | `false` | Whether to enable optimistic target type resolution. If enabled, this allows to pick a target type even if there are multiple matching classes (which would normally end with an `AmbiguousTargetTypeException`). | -| `preferSuperclass` | `false` | Allows to further specify optimistic target type resolution. By default, any of the target classes may be selected. Setting this to `true` will make the resolver attempt to select a superclass of the matching classes (if it is also in the target set). | -| `serializeDatetimeAsMillis` | `false` | Whether to serialize datetime values as millis since Unix epoch. If false, datetime value are serialize as string in ISO format (default). | -| `datetimeFormat` | | Format in which datetime values are serialized (and expected for deserialization). Default is undefined, meaning that the ISO 8601 format is used. | +| Parameter | Default value | Explanation | +|----------------------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `ignoreUnknownProperties` | `false` | Whether to ignore unknown properties when deserializing JSON-LD. Default behavior throws an exception. | +| `scanPackage` | `""` | Package in which the library should look for mapped classes. The scan is important for support for polymorphism in object deserialization. It is highly recommended to specify this value, otherwise the library will attempt to load and scan all classes on the classpath. | +| `requireId` | `false` | Whether to require an identifier when serializing an object. If set to `true` and no identifier is found (either there is no `@Id` field or its value is `null`), an exception will be thrown. By default a blank node identifier is generated if no id is present. | +| `assumeTargetType` | `false` | Whether to allow assuming target type in case the JSON-LD object does not contain types (`@type`). If set to `true`, the provided Java type (deserialization invocation argument, field type) will be used as target type. | +| `enableOptimisticTargetTypeResolution` | `false` | Whether to enable optimistic target type resolution. If enabled, this allows to pick a target type even if there are multiple matching classes (which would normally end with an `AmbiguousTargetTypeException`). | +| `preferSuperclass` | `false` | Allows to further specify optimistic target type resolution. By default, any of the target classes may be selected. Setting this to `true` will make the resolver attempt to select a superclass of the matching classes (if it is also in the target set). | +| `serializeDatetimeAsMillis` | `false` | Whether to serialize datetime values as millis since Unix epoch. If false, datetime value are serialize as string in ISO format (default). | +| `datetimeFormat` | | Format in which datetime values are serialized (and expected for deserialization). Default is undefined, meaning that the ISO 8601 format is used. | +| `serializeIndividualsUsingExpandedDefinition` | `false` | Whether individuals should be serialized as string with expanded term definition in context (consisting of `@id` and `@type`) Relevant only for context-based serializer. | See `cz.cvut.kbss.jsonld.ConfigParam`. ## Documentation -Documentation is on the [Wiki](https://github.com/kbss-cvut/jb4jsonld/wiki). API Javadoc is also [available](https://kbss.felk.cvut.cz/jenkins/view/Java%20Tools/job/jaxb-jsonld/javadoc/). +Documentation is on the [Wiki](https://github.com/kbss-cvut/jb4jsonld/wiki). API Javadoc is +also [available](https://kbss.felk.cvut.cz/jenkins/view/Java%20Tools/job/jaxb-jsonld/javadoc/). ## Getting JB4JSON-LD @@ -115,14 +118,15 @@ There are two ways to get JB4JSON-LD: * Use a [Maven dependency](http://search.maven.org/#search%7Cga%7C1%7Ccz.cvut.kbss.jsonld): ```XML + cz.cvut.kbss.jsonld jb4jsonld ``` -Note that you will most likely need an integration with a JSON-serialization library like [JB4JSON-LD-Jackson](https://github.com/kbss-cvut/jb4jsonld-jackson). - +Note that you will most likely need an integration with a JSON-serialization library +like [JB4JSON-LD-Jackson](https://github.com/kbss-cvut/jb4jsonld-jackson). ## License diff --git a/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java b/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java index 3abcea7..83633d8 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java +++ b/src/main/java/cz/cvut/kbss/jsonld/ConfigParam.java @@ -105,7 +105,7 @@ public enum ConfigParam { * Whether to serialize individuals using expanded term definition in context. * * This basically means that the individual's identifier is provided directly as a string and an expanded term - * definition is added into the context, specifying that the string is an identifier. + * definition (consisting of a {@literal @id} and {@literal @type}) is added into the context, specifying that the string is an identifier. */ SERIALIZE_INDIVIDUALS_USING_EXPANDED_DEFINITION("serializeIndividualsUsingExpandedDefinition");