* This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any * later version. - * + *
* This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more @@ -20,6 +20,7 @@ import cz.cvut.kbss.jsonld.annotation.JsonLdAttributeOrder; import cz.cvut.kbss.jsonld.exception.JsonLdSerializationException; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; @@ -70,7 +71,72 @@ public static String getOwlClass(Class> cls) { if (owlClass == null) { throw new IllegalArgumentException(cls + " is not an OWL class entity."); } - return owlClass.iri(); + return expandIriIfNecessary(owlClass.iri(), cls); + } + + /** + * Attempts to expand the specified IRI in case it is compacted (see {@link IdentifierUtil#isCompactIri(String)}) using JOPA namespace declarations. + *
+ * If the IRI is not compact or no matching namespace is found, the original IRI is returned. + * + * @param iri IRI to expand (if necessary and possible) + * @param declaringClass Class in/on which the IRI is declared. It is used as base for namespace search + * @return Expanded IRI if it was possible to expand it, original argument if not + * @see IdentifierUtil#isCompactIri(String) + * @see Namespaces + * @see Namespace + */ + public static String expandIriIfNecessary(String iri, Class> declaringClass) { + Objects.requireNonNull(declaringClass); + return IdentifierUtil.isCompactIri(iri) ? expandIri(iri, declaringClass).orElse(iri) : iri; + } + + /** + * Attempts to expand the specified compact IRI by finding a corresponding {@link Namespace} annotation in the specified class's ancestor hierarchy. + *
+ * That is, it tries to find a {@link Namespace} annotation with matching prefix on the specified class or any of its ancestors. If such an annotation + * is found, its namespace is concatenated with the suffix from the specified {@code iri} to produce the expanded version of the IRI. + *
+ * If no matching {@link Namespace} annotation is found, an empty {@link Optional} is returned.
+ *
+ * @param iri Compact IRI to expand
+ * @param declaringClass Class in which the IRI was declared. Used to start search for namespace declaration
+ * @return Expanded IRI if a matching namespace declaration is found, empty {@code Optional} if not
+ */
+ private static Optional
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -14,6 +14,7 @@
*/
package cz.cvut.kbss.jsonld.common;
+import java.util.Objects;
import java.util.Random;
/**
@@ -40,4 +41,22 @@ public class IdentifierUtil {
public static String generateBlankNodeId() {
return B_NODE_PREFIX + RANDOM.nextInt(Integer.MAX_VALUE);
}
+
+ /**
+ * Checks whether the specified value is a compact IRI, as defined by the JSON-LD specification
+ * par. 4.1.5.
+ *
+ * @param value The value to examine
+ * @return {@code true} if the specified value is a compact IRI, {@code false} otherwise
+ */
+ public static boolean isCompactIri(String value) {
+ Objects.requireNonNull(value);
+ final int colonIndex = value.indexOf(':');
+ if (colonIndex >= 0) {
+ final String prefixWithColon = value.substring(0, colonIndex + 1);
+ final String suffix = value.substring(colonIndex + 1);
+ return !B_NODE_PREFIX.equals(prefixWithColon) && !suffix.startsWith("//");
+ }
+ return false;
+ }
}
diff --git a/src/main/java/cz/cvut/kbss/jsonld/deserialization/DefaultInstanceBuilder.java b/src/main/java/cz/cvut/kbss/jsonld/deserialization/DefaultInstanceBuilder.java
index ac052e7..294e24f 100644
--- a/src/main/java/cz/cvut/kbss/jsonld/deserialization/DefaultInstanceBuilder.java
+++ b/src/main/java/cz/cvut/kbss/jsonld/deserialization/DefaultInstanceBuilder.java
@@ -111,20 +111,19 @@ public
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -14,11 +14,11 @@
*/
package cz.cvut.kbss.jsonld.common;
-import cz.cvut.kbss.jopa.model.annotations.Id;
-import cz.cvut.kbss.jopa.model.annotations.OWLAnnotationProperty;
-import cz.cvut.kbss.jopa.model.annotations.OWLClass;
-import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
+import cz.cvut.kbss.jopa.model.annotations.*;
+import cz.cvut.kbss.jopa.vocabulary.DC;
+import cz.cvut.kbss.jopa.vocabulary.RDF;
import cz.cvut.kbss.jopa.vocabulary.RDFS;
+import cz.cvut.kbss.jopa.vocabulary.SKOS;
import cz.cvut.kbss.jsonld.JsonLd;
import cz.cvut.kbss.jsonld.annotation.JsonLdAttributeOrder;
import cz.cvut.kbss.jsonld.annotation.JsonLdProperty;
@@ -33,6 +33,7 @@
import java.util.*;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@@ -218,6 +219,48 @@ void getOwlClassThrowsIllegalArgumentWhenNonOwlClassJavaTypeIsPassedAsArgument()
assertEquals(Integer.class + " is not an OWL class entity.", result.getMessage());
}
+ @Test
+ void getOwlClassExpandsIriIfItUsesNamespacePrefix() {
+ assertEquals(DC.Terms.AGENT, BeanAnnotationProcessor.getOwlClass(ClassWithNamespace.class));
+ }
+
+ @Namespace(prefix = "dc", namespace = DC.Terms.NAMESPACE)
+ @OWLClass(iri = "dc:Agent")
+ private static class ClassWithNamespace {
+ }
+
+ @Test
+ void getOWLClassExpandsIriBasedOnNamespacesDeclarationIfItUsesPrefix() {
+ assertEquals(SKOS.CONCEPT, BeanAnnotationProcessor.getOwlClass(ClassWithNamespaces.class));
+ }
+
+ @Namespaces({@Namespace(prefix = "rdf", namespace = RDF.NAMESPACE),
+ @Namespace(prefix = "skos", namespace = SKOS.NAMESPACE)})
+ @OWLClass(iri = "skos:Concept")
+ private static class ClassWithNamespaces {
+
+ @OWLDataProperty(iri = "skos:prefLabel")
+ private String prefLabel;
+
+ @OWLObjectProperty(iri = "rdfs:range")
+ private URI range;
+ }
+
+ @Test
+ void getOWLClassExpandsIriBasedOnNamespaceDeclaredInAncestorIfItUsesPrefix() {
+ assertEquals(SKOS.CONCEPT_SCHEME, BeanAnnotationProcessor.getOwlClass(ClassWithParentNamespaces.class));
+ }
+
+ @OWLClass(iri = "skos:ConceptScheme")
+ private static class ClassWithParentNamespaces extends ClassWithNamespaces {
+ }
+
+ @Test
+ void getOwlClassesExpandsCompactIrisBasedOnNamespaces() {
+ final Set
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -21,6 +21,7 @@
import cz.cvut.kbss.jsonld.deserialization.util.TypeMap;
import cz.cvut.kbss.jsonld.environment.Vocabulary;
import cz.cvut.kbss.jsonld.environment.model.Study;
+import cz.cvut.kbss.jsonld.environment.model.StudyWithNamespaces;
import cz.cvut.kbss.jsonld.environment.model.User;
import cz.cvut.kbss.jsonld.exception.JsonLdDeserializationException;
import org.junit.jupiter.api.Test;
@@ -28,6 +29,8 @@
import java.lang.reflect.Field;
import static cz.cvut.kbss.jsonld.environment.TestUtil.readAndExpand;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
import static org.junit.jupiter.api.Assertions.*;
class JsonLdDeserializerTest {
@@ -64,4 +67,13 @@ void deserializationThrowsJsonLdDeserializationExceptionWhenInputIsNotValidJsonL
final Object input = readAndExpand("invalidJsonLd.json");
assertThrows(JsonLdDeserializationException.class, () -> deserializer.deserialize(input, User.class));
}
+
+ @Test
+ void constructionExpandsCompactIrisWhenBuildingTypeMap() throws Exception {
+ final Configuration config = new Configuration();
+ config.set(ConfigParam.SCAN_PACKAGE, "cz.cvut.kbss.jsonld.environment.model");
+ final JsonLdDeserializer deserializer = JsonLdDeserializer.createExpandedDeserializer(config);
+ assertFalse(typeMap(deserializer).get(Vocabulary.STUDY).isEmpty());
+ assertThat(typeMap(deserializer).get(Vocabulary.STUDY), hasItem(StudyWithNamespaces.class));
+ }
}
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 65558a2..32a0133 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
@@ -693,4 +693,22 @@ void deserializationThrowsAmbiguousTargetTypeExceptionForAmbiguousTargetTypeWith
final Object input = readAndExpand("objectWithPluralOptimisticallyTypedReference.json");
assertThrows(AmbiguousTargetTypeException.class, () -> sut.deserialize(input, StudyOnPersons.class));
}
+
+ @Test
+ void deserializationEnsuresEqualityAndHashCodeBasedCollectionsArePopulatedCorrectly() throws Exception {
+ final Object input = readAndExpand("objectWithPluralReference.json");
+ final Organization result = sut.deserialize(input, Organization.class);
+ assertFalse(result.getEmployees().isEmpty());
+ result.getEmployees().forEach(e -> assertFalse(result.getEmployees().add(e)));
+ }
+
+ @Test
+ void deserializationSupportsCompactedIrisBasedOnJOPANamespaces() throws Exception {
+ sut.configuration().set(ConfigParam.IGNORE_UNKNOWN_PROPERTIES, Boolean.toString(true));
+ final Object input = readAndExpand("objectWithReadOnlyPropertyValue.json");
+ final StudyWithNamespaces result = sut.deserialize(input, StudyWithNamespaces.class);
+ assertEquals("LupusStudy", result.getName());
+ assertFalse(result.getMembers().isEmpty());
+ assertFalse(result.getParticipants().isEmpty());
+ }
}
diff --git a/src/test/java/cz/cvut/kbss/jsonld/deserialization/reference/PendingReferenceRegistryTest.java b/src/test/java/cz/cvut/kbss/jsonld/deserialization/reference/PendingReferenceRegistryTest.java
index 2a8bb16..3788378 100644
--- a/src/test/java/cz/cvut/kbss/jsonld/deserialization/reference/PendingReferenceRegistryTest.java
+++ b/src/test/java/cz/cvut/kbss/jsonld/deserialization/reference/PendingReferenceRegistryTest.java
@@ -129,8 +129,10 @@ void resolveReferencesSupportsMultiplePendingReferences() throws Exception {
final Organization referencedObject = Generator.generateOrganization();
final String iri = referencedObject.getUri().toString();
final Employee targetObject = new Employee();
+ targetObject.setUri(Generator.generateUri());
final Field targetField = Employee.class.getDeclaredField("employer");
final Employee targetTwo = new Employee();
+ targetTwo.setUri(Generator.generateUri());
pendingReferences.put(iri, new HashSet<>(Arrays.asList(
new SingularPendingReference(targetObject, targetField),
new SingularPendingReference(targetTwo, targetField))));
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 d1494c4..997b861 100644
--- a/src/test/java/cz/cvut/kbss/jsonld/environment/Vocabulary.java
+++ b/src/test/java/cz/cvut/kbss/jsonld/environment/Vocabulary.java
@@ -1,11 +1,11 @@
/**
* Copyright (C) 2020 Czech Technical University in Prague
- *
+ *
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -14,35 +14,39 @@
*/
package cz.cvut.kbss.jsonld.environment;
+import cz.cvut.kbss.jopa.vocabulary.DC;
+
public class Vocabulary {
+ public static final String DEFAULT_PREFIX = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/";
+
public static final String PERSON = "http://onto.fel.cvut.cz/ontologies/ufo/Person";
- public static final String USER = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/User";
- public static final String EMPLOYEE = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/Employee";
- public static final String ORGANIZATION = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/Organization";
- public static final String STUDY = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/Study";
+ public static final String USER = DEFAULT_PREFIX + "User";
+ public static final String EMPLOYEE = DEFAULT_PREFIX + "Employee";
+ public static final String ORGANIZATION = DEFAULT_PREFIX + "Organization";
+ public static final String STUDY = DEFAULT_PREFIX + "Study";
public static final String AGENT = "http://onto.fel.cvut.cz/ontologies/ufo/Agent";
- public static final String OBJECT_WITH_ANNOTATIONS = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/ObjectWithAnnotations";
- public static final String GENERIC_MEMBER = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/GenericMember";
+ public static final String OBJECT_WITH_ANNOTATIONS = DEFAULT_PREFIX + "ObjectWithAnnotations";
+ public static final String GENERIC_MEMBER = DEFAULT_PREFIX + "GenericMember";
public static final String FIRST_NAME = "http://xmlns.com/foaf/0.1/firstName";
public static final String LAST_NAME = "http://xmlns.com/foaf/0.1/lastName";
public static final String USERNAME = "http://xmlns.com/foaf/0.1/accountName";
public static final String KNOWS = "http://xmlns.com/foaf/0.1/knows";
- public static final String DATE_CREATED = "http://purl.org/dc/terms/created";
- public static final String IS_MEMBER_OF = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/isMemberOf";
- public static final String HAS_MEMBER = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/hasMember";
- public static final String HAS_PARTICIPANT = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/hasParticipant";
- public static final String HAS_ADMIN = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/hasAdmin";
- public static final String BRAND = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/brand";
- public static final String IS_ADMIN = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/isAdmin";
- public static final String ORIGIN = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/origin";
- public static final String HAS_EVENT_TYPE = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/hasEventType";
- public static final String ROLE = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/role";
- public static final String PASSWORD = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/password";
- public static final String NUMBER_OF_PEOPLE_INVOLVED = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/numberOfPeopleInvolved";
+ public static final String DATE_CREATED = DC.Terms.NAMESPACE + "created";
+ public static final String IS_MEMBER_OF = DEFAULT_PREFIX + "isMemberOf";
+ public static final String HAS_MEMBER = DEFAULT_PREFIX + "hasMember";
+ public static final String HAS_PARTICIPANT = DEFAULT_PREFIX + "hasParticipant";
+ public static final String HAS_ADMIN = DEFAULT_PREFIX + "hasAdmin";
+ public static final String BRAND = DEFAULT_PREFIX + "brand";
+ public static final String IS_ADMIN = DEFAULT_PREFIX + "isAdmin";
+ public static final String ORIGIN = DEFAULT_PREFIX + "origin";
+ public static final String HAS_EVENT_TYPE = DEFAULT_PREFIX + "hasEventType";
+ public static final String ROLE = DEFAULT_PREFIX + "role";
+ public static final String PASSWORD = DEFAULT_PREFIX + "password";
+ public static final String NUMBER_OF_PEOPLE_INVOLVED = DEFAULT_PREFIX + "numberOfPeopleInvolved";
- public static final String CHANGED_VALUE = "http://krizik.felk.cvut.cz/ontologies/jb4jsonld/changedValue";
+ public static final String CHANGED_VALUE = DEFAULT_PREFIX + "changedValue";
private Vocabulary() {
throw new AssertionError();
diff --git a/src/test/java/cz/cvut/kbss/jsonld/environment/model/Employee.java b/src/test/java/cz/cvut/kbss/jsonld/environment/model/Employee.java
index 6deb855..4768979 100644
--- a/src/test/java/cz/cvut/kbss/jsonld/environment/model/Employee.java
+++ b/src/test/java/cz/cvut/kbss/jsonld/environment/model/Employee.java
@@ -1,16 +1,14 @@
/**
* Copyright (C) 2020 Czech Technical University in Prague
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details. You should have received a copy of the GNU General Public License
- * along with this program. If not, see
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details. You should have received a copy of the GNU General Public License along with this program. If not, see
+ *