Skip to content

Commit

Permalink
[Bug #8] Added support for deserialization of objects into @properties.
Browse files Browse the repository at this point in the history
  • Loading branch information
ledsoft committed Jul 18, 2018
1 parent 5d95c75 commit 7a53339
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ private Object getKnownInstance(String nodeId) {
@Override
public void addNodeReference(String nodeId) {
final Class<?> targetType = getCurrentCollectionElementType();
if (BeanClassProcessor.isIdentifierType(targetType)) {
if (BeanClassProcessor.isIdentifierType(targetType) || targetType == null) {
currentInstance.addItem(nodeId);
} else {
currentInstance.addItem(getKnownInstance(nodeId));
Expand Down Expand Up @@ -275,4 +275,9 @@ public boolean isPropertyMapped(String property) {
public Class<?> getCurrentContextType() {
return currentInstance.getInstanceType();
}

@Override
public boolean isCurrentCollectionProperties() {
return currentInstance instanceof PropertiesInstanceContext;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/**
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
* <p>
* 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.
* <p>
* 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
* <http://www.gnu.org/licenses/>.
*/
package cz.cvut.kbss.jsonld.deserialization;

Expand All @@ -30,7 +28,8 @@ public interface InstanceBuilder {
* Creates new instance to fill filled mapped by the specified property.
* <p>
* The instance type is determined from the declared type of the mapped field, which is taken from the currently
* open object, and from the specified types. Therefore, another object has to be already open before this method can be called.
* open object, and from the specified types. Therefore, another object has to be already open before this method
* can be called.
* <p>
* The new instance also becomes the currently open object.
* <p>
Expand All @@ -39,7 +38,7 @@ public interface InstanceBuilder {
* <p>
* This method assumes that the property is mapped, i.e. that {@link #isPropertyMapped(String)} returned true.
*
* @param id Identifier of the object being open
* @param id Identifier of the object being open
* @param property Property identifier (IRI)
* @param types Types of the object being open
* @throws IllegalStateException If there is no {@link OWLClass} instance open
Expand All @@ -56,7 +55,7 @@ public interface InstanceBuilder {
* This method is intended for creating top level objects or adding objects to collections. Use {@link
* #openObject(String, String, List)} for opening objects as values of attributes.
*
* @param id Identifier of the object being open
* @param id Identifier of the object being open
* @param cls Java type of the object being open
* @see #openObject(String, String, List)
*/
Expand Down Expand Up @@ -178,6 +177,15 @@ public interface InstanceBuilder {
*/
Class<?> getCurrentCollectionElementType();

/**
* Checks whether the current collection context represents a {@link cz.cvut.kbss.jopa.model.annotations.Properties}
* attribute.
*
* @return {@code true} if the current context is a collection representing a {@link
* cz.cvut.kbss.jopa.model.annotations.Properties} field
*/
boolean isCurrentCollectionProperties();

/**
* Gets the Java type of the current object context.
*
Expand All @@ -190,8 +198,8 @@ public interface InstanceBuilder {
* <p>
* This method assumes that the property is mapped, i.e. that {@link #isPropertyMapped(String)} returned true.
* <p>
* Note that {@link Types} and {@link cz.cvut.kbss.jopa.model.annotations.Properties}
* fields are always treated as plural.
* Note that {@link Types} and {@link cz.cvut.kbss.jopa.model.annotations.Properties} fields are always treated as
* plural.
*
* @param property Property identifier (IRI)
* @return Whether mapped field is collection-valued or not
Expand All @@ -202,8 +210,8 @@ public interface InstanceBuilder {
* Checks whether the specified property is mapped by the class representing the current instance context.
* <p>
* Returns true also for the {@link cz.cvut.kbss.jsonld.JsonLd#TYPE} property, even though the target instance may
* not contain a {@link Types} field. The builder has to be able to handle types
* no matter whether a types field is present or not.
* not contain a {@link Types} field. The builder has to be able to handle types no matter whether a types field is
* present or not.
*
* @param property Property identifier (IRI)
* @return Whether the property is mapped in the current instance context
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/**
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
* <p>
* 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.
* <p>
* 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
* <http://www.gnu.org/licenses/>.
*/
package cz.cvut.kbss.jsonld.deserialization;

Expand Down Expand Up @@ -58,4 +56,11 @@ void addItem(Object item) {
instance.put(typedProperty, typedValue);
}
}

@Override
Class<?> getItemType() {
final Class<?> mapValueType = BeanClassProcessor.getMapValueType(propertiesField);
return Collection.class.isAssignableFrom(mapValueType) ?
BeanClassProcessor.getMapGenericValueType(propertiesField) : mapValueType;
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
/**
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
* <p>
* 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.
* <p>
* 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
* <http://www.gnu.org/licenses/>.
*/
package cz.cvut.kbss.jsonld.deserialization.expanded;

import cz.cvut.kbss.jsonld.JsonLd;
import cz.cvut.kbss.jsonld.deserialization.InstanceBuilder;
import cz.cvut.kbss.jsonld.exception.MissingIdentifierException;

import java.net.URI;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -59,6 +59,13 @@ private void resolveValue(Map<?, ?> value) {
instanceBuilder.addValue(value.get(JsonLd.VALUE));
} else if (value.size() == 1 && value.containsKey(JsonLd.ID)) {
instanceBuilder.addNodeReference(value.get(JsonLd.ID).toString());
} else if (instanceBuilder.isCurrentCollectionProperties()) {
// If we are deserializing an object into @Properties, just extract the identifier and put it into the map
if (!value.containsKey(JsonLd.ID)) {
throw new MissingIdentifierException(
"Cannot put an object without an identifier into @Properties. Object: " + value);
}
instanceBuilder.addValue(URI.create(value.get(JsonLd.ID).toString()));
} else {
final Class<?> elementType = instanceBuilder.getCurrentCollectionElementType();
new ObjectDeserializer(instanceBuilder, config, elementType).processValue(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package cz.cvut.kbss.jsonld.deserialization.expanded;

import cz.cvut.kbss.jsonld.Configuration;
import cz.cvut.kbss.jsonld.JsonLd;
import cz.cvut.kbss.jsonld.deserialization.DefaultInstanceBuilder;
import cz.cvut.kbss.jsonld.deserialization.InstanceBuilder;
import cz.cvut.kbss.jsonld.deserialization.util.TargetClassResolver;
import cz.cvut.kbss.jsonld.deserialization.util.TypeMap;
import cz.cvut.kbss.jsonld.environment.Generator;
import cz.cvut.kbss.jsonld.environment.TestUtil;
import cz.cvut.kbss.jsonld.environment.Vocabulary;
import cz.cvut.kbss.jsonld.environment.model.Person;
import cz.cvut.kbss.jsonld.exception.MissingIdentifierException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertTrue;

public class CollectionDeserializerTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void processValueAddsObjectIdentifiersIntoPropertiesMap() throws Exception {
final Map<?, ?> jsonLd = (Map<?, ?>) ((List) TestUtil.readAndExpand("objectWithPluralReference.json")).get(0);
final List<?> collection = (List<?>) jsonLd.get(Vocabulary.HAS_MEMBER);
final TargetClassResolver resolver = new TargetClassResolver(new TypeMap());
final InstanceBuilder instanceBuilder = new DefaultInstanceBuilder(resolver);
final DeserializerConfig config = new DeserializerConfig(new Configuration(), resolver);
final CollectionDeserializer deserializer = new CollectionDeserializer(instanceBuilder, config,
Vocabulary.HAS_MEMBER);
instanceBuilder.openObject(Generator.generateUri().toString(), Person.class);
deserializer.processValue(collection);
final Person person = (Person) instanceBuilder.getCurrentRoot();
final Set<?> values = person.getProperties().get(Vocabulary.HAS_MEMBER);
assertTrue(values.contains(TestUtil.HALSEY_URI.toString()));
assertTrue(values.contains(TestUtil.LASKY_URI.toString()));
assertTrue(values.contains(TestUtil.PALMER_URI.toString()));
}

@Test
public void processValueThrowsMissingIdentifierExceptionWhenInstanceToBeAddedIntoPropertiesHasNoIdentifier()
throws Exception {
final Map<?, ?> jsonLd = (Map<?, ?>) ((List) TestUtil.readAndExpand("objectWithPluralReference.json")).get(0);
final List<?> collection = (List<?>) jsonLd.get(Vocabulary.HAS_MEMBER);
final Map<?, ?> item = (Map<?, ?>) collection.get(0);
item.remove(JsonLd.ID);
final TargetClassResolver resolver = new TargetClassResolver(new TypeMap());
final InstanceBuilder instanceBuilder = new DefaultInstanceBuilder(resolver);
final DeserializerConfig config = new DeserializerConfig(new Configuration(), resolver);
final CollectionDeserializer deserializer = new CollectionDeserializer(instanceBuilder, config,
Vocabulary.HAS_MEMBER);
instanceBuilder.openObject(Generator.generateUri().toString(), Person.class);
thrown.expect(MissingIdentifierException.class);
thrown.expectMessage(containsString("Cannot put an object without an identifier into @Properties. Object: "));
deserializer.processValue(collection);
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
/**
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
* <p>
* 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.
* <p>
* 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
* <http://www.gnu.org/licenses/>.
*/
package cz.cvut.kbss.jsonld.deserialization.expanded;

import cz.cvut.kbss.jopa.model.annotations.Id;
import cz.cvut.kbss.jopa.model.annotations.OWLClass;
import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty;
import cz.cvut.kbss.jopa.model.annotations.Properties;
import cz.cvut.kbss.jopa.model.annotations.*;
import cz.cvut.kbss.jsonld.ConfigParam;
import cz.cvut.kbss.jsonld.Configuration;
import cz.cvut.kbss.jsonld.deserialization.JsonLdDeserializer;
import cz.cvut.kbss.jsonld.environment.TestUtil;
import cz.cvut.kbss.jsonld.environment.Vocabulary;
import cz.cvut.kbss.jsonld.environment.model.*;
import cz.cvut.kbss.jsonld.exception.JsonLdDeserializationException;
Expand All @@ -46,7 +42,6 @@ public class ExpandedJsonLdDeserializerTest {

private static final Map<URI, User> USERS = initUsers();

private static final URI ORG_URI = URI.create("http://krizik.felk.cvut.cz/ontologies/jb4jsonld#UNSC");
private static final String ORG_NAME = "UNSC";
private static final String[] ORG_BRANDS = {"Spartan-II", "Mjolnir IV"};

Expand Down Expand Up @@ -93,7 +88,7 @@ public void testDeserializeInstanceWithSingularObjectProperty() throws Exception
}

private void verifyOrganizationAttributes(Organization result) {
assertEquals(ORG_URI, result.getUri());
assertEquals(TestUtil.UNSC_URI, result.getUri());
assertEquals(ORG_NAME, result.getName());
assertNotNull(result.getDateCreated());
for (String brand : ORG_BRANDS) {
Expand Down Expand Up @@ -437,4 +432,38 @@ public void deserializationReconstructsObjectFromMultiplePlaces() throws Excepti
final Employee result = deserializer.deserialize(input, Employee.class);
verifyUserAttributes(USERS.get(HALSEY_URI), result);
}

@Test
public void deserializationPutsUnmappedObjectReferencesIntoProperties() throws Exception {
final Object input = readAndExpand("objectWithSingularReference.json");
final PersonWithoutSubclass result = deserializer.deserialize(input, PersonWithoutSubclass.class);
assertTrue(result.properties.containsKey(Vocabulary.IS_MEMBER_OF));
assertTrue(result.properties.get(Vocabulary.IS_MEMBER_OF).contains(TestUtil.UNSC_URI.toString()));
assertTrue(result.properties.containsKey(Vocabulary.USERNAME));
assertTrue(result.properties.get(Vocabulary.USERNAME).contains("halsey@unsc.org"));
}

@OWLClass(iri = Vocabulary.PERSON)
public static class PersonWithoutSubclass {

@Id
public URI uri;

@OWLDataProperty(iri = Vocabulary.FIRST_NAME)
private String firstName;

@OWLDataProperty(iri = Vocabulary.LAST_NAME)
private String lastName;

@Properties
private Map<String, Set<String>> properties;
}

@Test
public void deserializationPutsUnmappedObjectReferencesIntoTypedProperties() throws Exception {
final Object input = readAndExpand("objectWithSingularReference.json");
final ClassWithProperties result = deserializer.deserialize(input, ClassWithProperties.class);
assertTrue(result.properties.containsKey(URI.create(Vocabulary.IS_MEMBER_OF)));
assertTrue(result.properties.get(URI.create(Vocabulary.IS_MEMBER_OF)).contains(TestUtil.UNSC_URI));
}
}

0 comments on commit 7a53339

Please sign in to comment.