From dc2a3f06d1ac0b46bcd4cbf683f0e22d207171d6 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Fri, 29 Jul 2016 15:45:16 +0200 Subject: [PATCH] Working on deserialization. --- pom.xml | 4 +- .../kbss/jsonld/jackson/JsonLdModule.java | 20 ++++++ .../JacksonJsonLdDeserializer.java | 69 +++++++++++++++++++ .../JsonLdDeserializerModifier.java | 19 +++++ .../JsonLdSerializerModifier.java | 2 +- .../jackson/environment/Environment.java | 30 ++++++++ .../JsonLdDeserializationTest.java | 53 ++++++++++++++ .../JsonLdSerializationTest.java | 20 ++++-- .../resources/objectWithDataProperties.json | 17 +++++ .../objectWithSingularReference.json | 25 +++++++ 10 files changed, 252 insertions(+), 7 deletions(-) create mode 100644 src/main/java/cz/cvut/kbss/jsonld/jackson/JsonLdModule.java create mode 100644 src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JacksonJsonLdDeserializer.java create mode 100644 src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JsonLdDeserializerModifier.java create mode 100644 src/test/java/cz/cvut/kbss/jsonld/jackson/environment/Environment.java create mode 100644 src/test/java/cz/cvut/kbss/jsonld/jackson/environment/deserialization/JsonLdDeserializationTest.java create mode 100644 src/test/resources/objectWithDataProperties.json create mode 100644 src/test/resources/objectWithSingularReference.json diff --git a/pom.xml b/pom.xml index f803283..0f949a2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ cz.cvut.kbss jaxb-jsonld-jackson - 0.0.1 + 0.0.2 JAXB JSON-LD Jackson JAXB JSON-LD integration for Jackson. @@ -40,7 +40,7 @@ cz.cvut.kbss jaxb-jsonld - 0.0.1 + 0.0.2 diff --git a/src/main/java/cz/cvut/kbss/jsonld/jackson/JsonLdModule.java b/src/main/java/cz/cvut/kbss/jsonld/jackson/JsonLdModule.java new file mode 100644 index 0000000..1baac76 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/jsonld/jackson/JsonLdModule.java @@ -0,0 +1,20 @@ +package cz.cvut.kbss.jsonld.jackson; + +import com.fasterxml.jackson.databind.module.SimpleModule; +import cz.cvut.kbss.jsonld.jackson.deserialization.JsonLdDeserializerModifier; +import cz.cvut.kbss.jsonld.jackson.serialization.JsonLdSerializerModifier; + +/** + * Simple module with pre-configured serializer and deserializer modifier. + */ +public class JsonLdModule extends SimpleModule { + + public JsonLdModule() { + init(); + } + + private void init() { + setSerializerModifier(new JsonLdSerializerModifier()); + setDeserializerModifier(new JsonLdDeserializerModifier()); + } +} diff --git a/src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JacksonJsonLdDeserializer.java b/src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JacksonJsonLdDeserializer.java new file mode 100644 index 0000000..997ad78 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JacksonJsonLdDeserializer.java @@ -0,0 +1,69 @@ +package cz.cvut.kbss.jsonld.jackson.deserialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; +import com.github.jsonldjava.core.JsonLdError; +import com.github.jsonldjava.core.JsonLdProcessor; +import cz.cvut.kbss.jsonld.deserialization.JsonLdDeserializer; +import cz.cvut.kbss.jsonld.exception.JsonLdDeserializationException; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class JacksonJsonLdDeserializer extends DelegatingDeserializer { + + private ObjectMapper mapper = new ObjectMapper(); + + private final Class resultType; + + public JacksonJsonLdDeserializer(JsonDeserializer delegatee, Class resultType) { + super(delegatee); + this.resultType = resultType; + } + + @Override + protected JsonDeserializer newDelegatingInstance(JsonDeserializer newDelegatee) { + // TODO Is the null ok? Perhaps we should use a different base class, we are not delegating deserialization to anything else anyway + return new JacksonJsonLdDeserializer(newDelegatee, null); + } + + @Override + public Object deserialize(JsonParser jp, DeserializationContext ctx) throws IOException { + try { + final Object input = parseJsonObject(jp); + final List expanded = JsonLdProcessor.expand(input); + final JsonLdDeserializer deserializer = JsonLdDeserializer.createExpandedDeserializer(); + return deserializer.deserialize(expanded, resultType); + } catch (JsonLdError e) { + throw new JsonLdDeserializationException("Unable to expand the input JSON.", e); + } + } + + private Object parseJsonObject(JsonParser parser) throws IOException { + Object value = null; + final JsonToken initialToken = parser.getCurrentToken(); + parser.setCodec(mapper); + if (initialToken == JsonToken.START_ARRAY) { + value = parser.readValueAs(new TypeReference>() { + }); + } else if (initialToken == JsonToken.START_OBJECT) { + value = parser.readValueAs(new TypeReference>() { + }); + } else if (initialToken == JsonToken.VALUE_STRING) { + value = parser.readValueAs(String.class); + } else if (initialToken == JsonToken.VALUE_FALSE || initialToken == JsonToken.VALUE_TRUE) { + value = parser.readValueAs(Boolean.class); + } else if (initialToken == JsonToken.VALUE_NUMBER_FLOAT || initialToken == JsonToken.VALUE_NUMBER_INT) { + value = parser.readValueAs(Number.class); + } else if (initialToken == JsonToken.VALUE_NULL) { + value = null; + } + return value; + } +} diff --git a/src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JsonLdDeserializerModifier.java b/src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JsonLdDeserializerModifier.java new file mode 100644 index 0000000..43810a2 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/jsonld/jackson/deserialization/JsonLdDeserializerModifier.java @@ -0,0 +1,19 @@ +package cz.cvut.kbss.jsonld.jackson.deserialization; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; +import cz.cvut.kbss.jsonld.common.BeanAnnotationProcessor; + +public class JsonLdDeserializerModifier extends BeanDeserializerModifier { + + @Override + public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, + JsonDeserializer deserializer) { + if (BeanAnnotationProcessor.isOwlClassEntity(beanDesc.getBeanClass())) { + return new JacksonJsonLdDeserializer(deserializer, beanDesc.getBeanClass()); + } + return deserializer; + } +} diff --git a/src/main/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializerModifier.java b/src/main/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializerModifier.java index efa0421..65c54b0 100644 --- a/src/main/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializerModifier.java +++ b/src/main/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializerModifier.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; -import cz.cvut.kbss.jsonld.serialization.BeanAnnotationProcessor; +import cz.cvut.kbss.jsonld.common.BeanAnnotationProcessor; /** * Main point of integration of the JSON-LD serialization implementation into Jackson. diff --git a/src/test/java/cz/cvut/kbss/jsonld/jackson/environment/Environment.java b/src/test/java/cz/cvut/kbss/jsonld/jackson/environment/Environment.java new file mode 100644 index 0000000..29eba50 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/jsonld/jackson/environment/Environment.java @@ -0,0 +1,30 @@ +package cz.cvut.kbss.jsonld.jackson.environment; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +public class Environment { + + /** + * Reads test data from the test resources classpath folder. + * + * @param fileName File to read + * @return Content of the file + */ + public static String readData(String fileName) { + final File file = new File(Environment.class.getClassLoader().getResource(fileName).getFile()); + assert file.exists(); + try (final BufferedReader reader = new BufferedReader(new FileReader(file))) { + final StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line).append('\n'); + } + return sb.toString(); + } catch (IOException e) { + throw new RuntimeException("Unable to read test file " + fileName, e); + } + } +} diff --git a/src/test/java/cz/cvut/kbss/jsonld/jackson/environment/deserialization/JsonLdDeserializationTest.java b/src/test/java/cz/cvut/kbss/jsonld/jackson/environment/deserialization/JsonLdDeserializationTest.java new file mode 100644 index 0000000..2a3c952 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/jsonld/jackson/environment/deserialization/JsonLdDeserializationTest.java @@ -0,0 +1,53 @@ +package cz.cvut.kbss.jsonld.jackson.environment.deserialization; + +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.jsonld.jackson.JsonLdModule; +import cz.cvut.kbss.jsonld.jackson.environment.Environment; +import cz.cvut.kbss.jsonld.jackson.environment.model.Employee; +import cz.cvut.kbss.jsonld.jackson.environment.model.User; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.net.URI; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class JsonLdDeserializationTest { + + private ObjectMapper objectMapper; + + @Before + public void setUp() { + this.objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JsonLdModule()); + } + + @Ignore + @Test + public void testDeserializeInstanceWithDataProperties() throws Exception { + final String input = Environment.readData("objectWithDataProperties.json"); + final User expected = new User(); + expected.setUri(URI.create("http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld#787088083")); + expected.setFirstName("Catherine"); + expected.setLastName("Halsey"); + expected.setUsername("halsey@unsc.org"); + expected.setAdmin(true); + final User result = objectMapper.readValue(input, User.class); + assertNotNull(result); + assertEquals(expected.getUri(), result.getUri()); + assertEquals(expected.getFirstName(), result.getFirstName()); + assertEquals(expected.getLastName(), result.getLastName()); + assertEquals(expected.getUsername(), result.getUsername()); + assertEquals(expected.getAdmin(), result.getAdmin()); + } + + @Ignore + @Test + public void testDeserializeInstanceWithSingularObjectProperty() throws Exception { + final String input = Environment.readData("objectWithSingularReference.json"); + final Employee result = objectMapper.readValue(input, Employee.class); + // TODO + } +} diff --git a/src/test/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializationTest.java b/src/test/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializationTest.java index e36e9c4..4fb0002 100644 --- a/src/test/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializationTest.java +++ b/src/test/java/cz/cvut/kbss/jsonld/jackson/serialization/JsonLdSerializationTest.java @@ -1,8 +1,8 @@ package cz.cvut.kbss.jsonld.jackson.serialization; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.github.jsonldjava.sesame.SesameJSONLDParserFactory; +import cz.cvut.kbss.jsonld.jackson.JsonLdModule; import cz.cvut.kbss.jsonld.jackson.environment.Generator; import cz.cvut.kbss.jsonld.jackson.environment.StatementCopyingHandler; import cz.cvut.kbss.jsonld.jackson.environment.Vocabulary; @@ -30,6 +30,8 @@ import java.io.IOException; import java.net.URI; import java.util.Date; +import java.util.HashSet; +import java.util.Set; import static org.junit.Assert.assertTrue; @@ -50,9 +52,7 @@ public void setUp() throws Exception { parser.setRDFHandler(new StatementCopyingHandler(connection)); this.objectMapper = new ObjectMapper(); - final SimpleModule module = new SimpleModule(); - module.setSerializerModifier(new JsonLdSerializerModifier()); - objectMapper.registerModule(module); + objectMapper.registerModule(new JsonLdModule()); } private void initRepository() throws Exception { @@ -168,4 +168,16 @@ public void testSerializeInstanceWithPluralReferenceAndBackwardReferences() thro verifyUserAttributes(emp); } } + + @Test + public void testSerializeCollectionOfInstances() throws Exception { + final Set users = new HashSet<>(); + for (int i = 0; i < Generator.randomCount(10); i++) { + users.add(Generator.generateUser()); + } + serializeAndStore(users); + for (User u : users) { + verifyUserAttributes(u); + } + } } diff --git a/src/test/resources/objectWithDataProperties.json b/src/test/resources/objectWithDataProperties.json new file mode 100644 index 0000000..92a5515 --- /dev/null +++ b/src/test/resources/objectWithDataProperties.json @@ -0,0 +1,17 @@ +{ + "@context": { + "firstName": "http://xmlns.com/foaf/0.1/firstName", + "lastName": "http://xmlns.com/foaf/0.1/lastName", + "accountName": "http://xmlns.com/foaf/0.1/accountName", + "isAdmin": "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/isAdmin" + }, + "@id": "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld#787088083", + "@type": [ + "http://onto.fel.cvut.cz/ontologies/ufo/Person", + "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/User" + ], + "isAdmin": true, + "accountName": "halsey@unsc.org", + "firstName": "Catherine", + "lastName": "Halsey" +} diff --git a/src/test/resources/objectWithSingularReference.json b/src/test/resources/objectWithSingularReference.json new file mode 100644 index 0000000..0f31b67 --- /dev/null +++ b/src/test/resources/objectWithSingularReference.json @@ -0,0 +1,25 @@ +{ + "@context": { + "firstName": "http://xmlns.com/foaf/0.1/firstName", + "lastName": "http://xmlns.com/foaf/0.1/lastName", + "accountName": "http://xmlns.com/foaf/0.1/accountName", + "isAdmin": "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/isAdmin" + }, + "@id": "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld#-697813743", + "@type": [ + "http://onto.fel.cvut.cz/ontologies/ufo/Person", + "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/Employee", + "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/User" + ], + "isAdmin": false, + "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/isMemberOf": { + "@id": "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld#-82218522", + "@type": "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/Organization", + "http://krizik.felk.cvut.cz/ontologies/jaxb-jsonld/brand": "Brandy0", + "http://purl.org/dc/terms/created": "Fri Jul 29 14:52:04 CEST 2016", + "http://www.w3.org/2000/01/rdf-schema#label": "Organization291065182" + }, + "accountName": "user647104078", + "firstName": "FirstName647104078", + "lastName": "LastName647104078" +}