diff --git a/pom.xml b/pom.xml index 9c083f5..c97dfa5 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,9 @@ + + src/main/resources + ua_parser ${basedir}/uap-core @@ -67,6 +70,9 @@ + + src/test/resources + ua_parser ${basedir}/uap-core/test_resources @@ -159,6 +165,12 @@ commons-collections4 4.1 + + com.fasterxml.jackson.core + jackson-databind + 2.8.3 + true + junit junit @@ -171,5 +183,17 @@ 1.3 test + + org.skyscreamer + jsonassert + 1.5.0 + test + + + commons-io + commons-io + 2.6 + test + diff --git a/src/main/java/ua_parser/ClientModule.java b/src/main/java/ua_parser/ClientModule.java new file mode 100644 index 0000000..ef13303 --- /dev/null +++ b/src/main/java/ua_parser/ClientModule.java @@ -0,0 +1,62 @@ +package ua_parser; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Class that registers capability of serializing objects with Jackson core. + * + * This module can be manually registered with Jackson: + *
+ *     ObjectMapper mapper = new ObjectMapper();
+ *     mapper.registerModule(new ClientModule());
+ * 
+ * + * This module also supports auto configuration as an SPI via the Java ServiceLoader api: + *
+ *     ObjectMapper mapper = new ObjectMapper();
+ *     mapper.findAndRegisterModules();
+ *
+ * 
+ * + * @author Adam J. Weigold + */ +public class ClientModule extends SimpleModule { + + public ClientModule() { + setMixInAnnotation(UserAgent.class, UserAgentMixin.class); + setMixInAnnotation(OS.class, OSMixin.class); + setMixInAnnotation(Device.class, DeviceMixin.class); + setMixInAnnotation(Client.class, ClientMixin.class); + } + + abstract static class UserAgentMixin { + @JsonCreator + public UserAgentMixin(@JsonProperty("family") String family, + @JsonProperty("major") String major, + @JsonProperty("minor") String minor, + @JsonProperty("patch") String patch) {} + } + + abstract static class OSMixin { + @JsonCreator + public OSMixin(@JsonProperty("family") String family, + @JsonProperty("major") String major, + @JsonProperty("minor") String minor, + @JsonProperty("patch") String patch, + @JsonProperty("patchMinor") String patchMinor) {} + } + + abstract static class DeviceMixin { + @JsonCreator + public DeviceMixin(@JsonProperty("family") String family) {} + } + + abstract static class ClientMixin { + @JsonCreator + public ClientMixin(@JsonProperty("userAgent") UserAgent userAgent, + @JsonProperty("os") OS os, + @JsonProperty("device") Device device) {} + } +} diff --git a/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module new file mode 100644 index 0000000..5601c50 --- /dev/null +++ b/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module @@ -0,0 +1 @@ +ua_parser.ClientModule \ No newline at end of file diff --git a/src/test/java/ua_parser/JacksonModuleDatabindingTest.java b/src/test/java/ua_parser/JacksonModuleDatabindingTest.java new file mode 100644 index 0000000..3e4dfe6 --- /dev/null +++ b/src/test/java/ua_parser/JacksonModuleDatabindingTest.java @@ -0,0 +1,43 @@ +package ua_parser; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.io.IOUtils; +import org.json.JSONException; +import org.junit.Test; +import org.skyscreamer.jsonassert.JSONAssert; + +import java.io.IOException; +import java.nio.charset.Charset; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class JacksonModuleDatabindingTest { + + @Test + public void testJacksonModuleSpiRegistration() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); + Class clientMixin = objectMapper.findMixInClassFor(Client.class); + assertTrue(clientMixin.isAssignableFrom(ClientModule.ClientMixin.class)); + } + + @Test + public void testJacksonSerializationAndDeserialization() throws IOException, JSONException { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); + + Client testClient = new Client(new UserAgent("Firefox", "3", "5", "5"), + new OS("Mac OS X", "10", "4", null, null), + new Device("Other")); + + String expectedSerialization = IOUtils.resourceToString( + "ua_parser/testClient.json", Charset.defaultCharset(), getClass().getClassLoader()); + + String actualSerialization = objectMapper.writeValueAsString(testClient); + JSONAssert.assertEquals(expectedSerialization, actualSerialization, true); + + Client deserializedClient = objectMapper.readValue(actualSerialization, Client.class); + assertEquals(testClient, deserializedClient); + } +} diff --git a/src/test/resources/ua_parser/testClient.json b/src/test/resources/ua_parser/testClient.json new file mode 100644 index 0000000..0c5e1d1 --- /dev/null +++ b/src/test/resources/ua_parser/testClient.json @@ -0,0 +1,18 @@ +{ + "userAgent": { + "family": "Firefox", + "major": "3", + "minor": "5", + "patch": "5" + }, + "os": { + "family": "Mac OS X", + "major": "10", + "minor": "4", + "patch": null, + "patchMinor": null + }, + "device": { + "family": "Other" + } +} \ No newline at end of file