From 7fc714c1cd221cdea1a66a0b574e916811281411 Mon Sep 17 00:00:00 2001 From: Neil Green Date: Wed, 17 Oct 2018 20:35:04 +0100 Subject: [PATCH 1/7] create JacksonMessageAdapter --- .gitignore | 2 + dependencies.gradle | 1 + scarlet-message-adapter-jackson/build.gradle | 77 ++++++++ .../jackson/JacksonMessageAdapter.kt | 38 ++++ .../jackson/JacksonMessageAdapterTest.kt | 179 ++++++++++++++++++ settings.gradle | 1 + 6 files changed, 298 insertions(+) create mode 100755 scarlet-message-adapter-jackson/build.gradle create mode 100644 scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt create mode 100644 scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt diff --git a/.gitignore b/.gitignore index ccc185ef..cb109586 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,5 @@ google-services.json freeline.py freeline/ freeline_project_description.json + +.gradletasknamecache diff --git a/dependencies.gradle b/dependencies.gradle index 122469c4..15ddaf94 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -30,6 +30,7 @@ ext { gson = 'com.google.code.gson:gson:2.8.2' protobuf = 'com.google.protobuf:protobuf-java:3.4.0' jacksonDatabind = 'com.fasterxml.jackson.core:jackson-databind:2.9.5' + jacksonModuleKotlin = 'com.fasterxml.jackson.module:jackson-module-kotlin:2.9.5' jsonPatch = 'com.github.fge:json-patch:1.9' dagger = 'com.google.dagger:dagger:2.12' diff --git a/scarlet-message-adapter-jackson/build.gradle b/scarlet-message-adapter-jackson/build.gradle new file mode 100755 index 00000000..6a2027d0 --- /dev/null +++ b/scarlet-message-adapter-jackson/build.gradle @@ -0,0 +1,77 @@ +apply plugin: 'kotlin' +apply plugin: 'java-library' +apply plugin: 'org.jetbrains.dokka' +apply plugin: 'maven-publish' + +dependencies { + api rootProject.ext.jacksonDatabind + api kotlinReflect + + implementation project(':scarlet-core') + implementation rootProject.ext.kotlinStdlib + + testImplementation project(':scarlet') + testImplementation project(':scarlet-websocket-mockwebserver') + testImplementation project(':scarlet-test-utils') + testImplementation rootProject.ext.junit + testImplementation rootProject.ext.mockito + testImplementation rootProject.ext.kotlinReflect + testImplementation rootProject.ext.assertJ + testImplementation rootProject.ext.jacksonModuleKotlin +} + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource +} + +task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) { + outputFormat = 'javadoc' + outputDirectory = javadoc.destinationDir + +// impliedPlatforms = ['JVM'] +// jdkVersion = 7 + + externalDocumentationLink { + url = new URL("https://docs.oracle.com/javase/7/docs/api/") + } +} + +task javadocJar(type: Jar, dependsOn: dokkaJavadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar, javadocJar +} + +publishing { + publications { + mavenJava(MavenPublication) { + groupId 'com.tinder' + version version + artifactId project.getName() + artifact sourcesJar + artifact javadocJar + from components.java + } + } +} + +artifactory { + contextUrl = 'https://tinder.jfrog.io/tinder' + publish { + repository { + repoKey = 'libs-release-local' + username = System.getenv("ARTIFACTORY_USER") + password = System.getenv("ARTIFACTORY_PASSWORD") + maven = true + } + defaults { + publications('mavenJava') + publishArtifacts = true + publishPom = true + } + } +} diff --git a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt new file mode 100644 index 00000000..b5efd89c --- /dev/null +++ b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt @@ -0,0 +1,38 @@ +package com.tinder.scarlet.messageadapter.jackson + +import com.fasterxml.jackson.databind.ObjectMapper +import com.tinder.scarlet.Message +import com.tinder.scarlet.MessageAdapter +import com.tinder.scarlet.utils.getRawType +import java.lang.reflect.Type + +class JacksonMessageAdapter private constructor( + private val objectMapper: ObjectMapper, + private val klass: Class +) : MessageAdapter { + + override fun fromMessage(message: Message): T { + return when (message) { + is Message.Text -> objectMapper.readValue(message.value, klass) + is Message.Bytes -> objectMapper.readValue(message.value, klass) + } + } + + override fun toMessage(data: T): Message { + val body = objectMapper.writeValueAsString(data) + return Message.Text(body) + } + + + class Factory constructor( + private val objectMapper: ObjectMapper = DEFAULT_OBJECT_MAPPER + ) : MessageAdapter.Factory { + override fun create(type: Type, annotations: Array): MessageAdapter<*> = + JacksonMessageAdapter(objectMapper, type.getRawType()) + + companion object { + private val DEFAULT_OBJECT_MAPPER = ObjectMapper() + } + } + +} diff --git a/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt b/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt new file mode 100644 index 00000000..7c16a456 --- /dev/null +++ b/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt @@ -0,0 +1,179 @@ +package com.tinder.scarlet.messageadapter.jackson + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.tinder.scarlet.Lifecycle +import com.tinder.scarlet.Message +import com.tinder.scarlet.MessageAdapter +import com.tinder.scarlet.Scarlet +import com.tinder.scarlet.Stream +import com.tinder.scarlet.WebSocket.Event +import com.tinder.scarlet.WebSocket.Event.OnConnectionOpened +import com.tinder.scarlet.lifecycle.LifecycleRegistry +import com.tinder.scarlet.testutils.TestStreamObserver +import com.tinder.scarlet.testutils.any +import com.tinder.scarlet.testutils.containingText +import com.tinder.scarlet.testutils.test +import com.tinder.scarlet.websocket.mockwebserver.newWebSocketFactory +import com.tinder.scarlet.websocket.okhttp.newWebSocketFactory +import com.tinder.scarlet.ws.Receive +import com.tinder.scarlet.ws.Send +import okhttp3.OkHttpClient +import okhttp3.mockwebserver.MockWebServer +import org.assertj.core.api.Assertions.assertThat +import org.junit.Rule +import org.junit.Test +import java.lang.reflect.Type +import java.util.concurrent.TimeUnit + +internal class JacksonMessageAdapterTest { + + @get:Rule + private val mockWebServer = MockWebServer() + private val serverUrlString by lazy { mockWebServer.url("/").toString() } + + private val serverLifecycleRegistry = LifecycleRegistry() + private lateinit var server: Service + private lateinit var serverEventObserver: TestStreamObserver + + private val clientLifecycleRegistry = LifecycleRegistry() + private lateinit var client: Service + private lateinit var clientEventObserver: TestStreamObserver + + @Test + fun sendAnInterface_shouldBeReceivedByTheServer() { + // Given + givenConnectionIsEstablished() + val data = AnImplementation("value") + val expectedString = """{"name":"value"}""" + val serverAnImplementationObserver = server.observeAnImplementation().test() + + // When + val isSuccessful = client.sendAnInterface(data) + + // Then + assertThat(isSuccessful).isTrue() + serverEventObserver.awaitValues( + any>(), + any().containingText(expectedString) + ) + serverAnImplementationObserver.awaitCount(1) + assertThat(serverAnImplementationObserver.values).containsExactly(data) + } + + @Test + fun sendAnImplementation_shouldBeReceivedByTheServer() { + // Given + givenConnectionIsEstablished() + val data = AnImplementation("value") + val expectedString = """{"name":"value"}""" + val serverAnImplementationObserver = server.observeAnImplementation().test() + + // When + val isSuccessful = client.sendAnImplementation(data) + + // Then + assertThat(isSuccessful).isTrue() + serverEventObserver.awaitValues( + any>(), + any().containingText(expectedString) + ) + serverAnImplementationObserver.awaitCount(1) + assertThat(serverAnImplementationObserver.values).containsExactly(data) + } + + private fun givenConnectionIsEstablished() { + createClientAndServer() + serverLifecycleRegistry.onNext(Lifecycle.State.Started) + clientLifecycleRegistry.onNext(Lifecycle.State.Started) + blockUntilConnectionIsEstablish() + } + + private fun createClientAndServer() { + val factory = JacksonMessageAdapter.Factory(createJackson()) + server = createServer(factory) + serverEventObserver = server.observeEvents().test() + client = createClient(factory) + clientEventObserver = client.observeEvents().test() + } + + private fun createJackson(): ObjectMapper = ObjectMapper() + .registerModule(KotlinModule()) + + private fun createServer(factory: JacksonMessageAdapter.Factory): Service { + val webSocketFactory = mockWebServer.newWebSocketFactory() + val scarlet = Scarlet.Builder() + .webSocketFactory(webSocketFactory) + .addMessageAdapterFactory(factory) + .lifecycle(serverLifecycleRegistry) + .build() + return scarlet.create() + } + + private fun createClient(factory: JacksonMessageAdapter.Factory): Service { + val okHttpClient = OkHttpClient.Builder() + .writeTimeout(500, TimeUnit.MILLISECONDS) + .readTimeout(500, TimeUnit.MILLISECONDS) + .build() + val webSocketFactory = okHttpClient.newWebSocketFactory(serverUrlString) + val scarlet = Scarlet.Builder() + .webSocketFactory(webSocketFactory) + .addMessageAdapterFactory(TextMessageAdapter.Factory()) + .addMessageAdapterFactory(factory) + .lifecycle(clientLifecycleRegistry) + .build() + return scarlet.create() + } + + private fun blockUntilConnectionIsEstablish() { + serverEventObserver.awaitValues( + any>() + ) + clientEventObserver.awaitValues( + any>() + ) + } + + + companion object { + + interface AnInterface { + val name: String? + } + + data class AnImplementation(override val name: String?) : AnInterface + + internal class TextMessageAdapter : MessageAdapter { + + override fun fromMessage(message: Message): String = (message as Message.Text).value + + override fun toMessage(data: String): Message = Message.Text(data) + + class Factory : MessageAdapter.Factory { + override fun create(type: Type, annotations: Array): MessageAdapter<*> = when (type) { + String::class.java -> TextMessageAdapter() + else -> throw IllegalArgumentException("$type is not supported.") + } + } + } + + + internal interface Service { + @Receive + fun observeEvents(): Stream + + @Send + fun sendString(message: String): Boolean + + @Send + fun sendAnImplementation(impl: AnImplementation): Boolean + + @Receive + fun observeAnImplementation(): Stream + + @Send + fun sendAnInterface(impl: AnInterface): Boolean + } + } + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index a2d468d9..9e6fb58c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,7 @@ include ':scarlet-websocket-mockwebserver' include ':scarlet-message-adapter-moshi' include ':scarlet-message-adapter-protobuf' include ':scarlet-message-adapter-gson' +include ':scarlet-message-adapter-jackson' include ':scarlet-stream-adapter-rxjava' include ':scarlet-stream-adapter-rxjava2' include ':scarlet-stream-adapter-coroutines' From 952a1513c02599c3b295e5f4bab869771222eef9 Mon Sep 17 00:00:00 2001 From: Neil Green Date: Wed, 17 Oct 2018 21:23:37 +0100 Subject: [PATCH 2/7] correct kotlin formatting --- .../jackson/JacksonMessageAdapter.kt | 10 ++--- .../jackson/JacksonMessageAdapterTest.kt | 43 +++++++++---------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt index b5efd89c..362ea812 100644 --- a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt +++ b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt @@ -7,8 +7,8 @@ import com.tinder.scarlet.utils.getRawType import java.lang.reflect.Type class JacksonMessageAdapter private constructor( - private val objectMapper: ObjectMapper, - private val klass: Class + private val objectMapper: ObjectMapper, + private val klass: Class ) : MessageAdapter { override fun fromMessage(message: Message): T { @@ -23,16 +23,14 @@ class JacksonMessageAdapter private constructor( return Message.Text(body) } - class Factory constructor( - private val objectMapper: ObjectMapper = DEFAULT_OBJECT_MAPPER + private val objectMapper: ObjectMapper = DEFAULT_OBJECT_MAPPER ) : MessageAdapter.Factory { override fun create(type: Type, annotations: Array): MessageAdapter<*> = - JacksonMessageAdapter(objectMapper, type.getRawType()) + JacksonMessageAdapter(objectMapper, type.getRawType()) companion object { private val DEFAULT_OBJECT_MAPPER = ObjectMapper() } } - } diff --git a/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt b/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt index 7c16a456..2b24d4da 100644 --- a/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt +++ b/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt @@ -54,8 +54,8 @@ internal class JacksonMessageAdapterTest { // Then assertThat(isSuccessful).isTrue() serverEventObserver.awaitValues( - any>(), - any().containingText(expectedString) + any>(), + any().containingText(expectedString) ) serverAnImplementationObserver.awaitCount(1) assertThat(serverAnImplementationObserver.values).containsExactly(data) @@ -75,8 +75,8 @@ internal class JacksonMessageAdapterTest { // Then assertThat(isSuccessful).isTrue() serverEventObserver.awaitValues( - any>(), - any().containingText(expectedString) + any>(), + any().containingText(expectedString) ) serverAnImplementationObserver.awaitCount(1) assertThat(serverAnImplementationObserver.values).containsExactly(data) @@ -98,43 +98,42 @@ internal class JacksonMessageAdapterTest { } private fun createJackson(): ObjectMapper = ObjectMapper() - .registerModule(KotlinModule()) + .registerModule(KotlinModule()) private fun createServer(factory: JacksonMessageAdapter.Factory): Service { val webSocketFactory = mockWebServer.newWebSocketFactory() val scarlet = Scarlet.Builder() - .webSocketFactory(webSocketFactory) - .addMessageAdapterFactory(factory) - .lifecycle(serverLifecycleRegistry) - .build() + .webSocketFactory(webSocketFactory) + .addMessageAdapterFactory(factory) + .lifecycle(serverLifecycleRegistry) + .build() return scarlet.create() } private fun createClient(factory: JacksonMessageAdapter.Factory): Service { val okHttpClient = OkHttpClient.Builder() - .writeTimeout(500, TimeUnit.MILLISECONDS) - .readTimeout(500, TimeUnit.MILLISECONDS) - .build() + .writeTimeout(500, TimeUnit.MILLISECONDS) + .readTimeout(500, TimeUnit.MILLISECONDS) + .build() val webSocketFactory = okHttpClient.newWebSocketFactory(serverUrlString) val scarlet = Scarlet.Builder() - .webSocketFactory(webSocketFactory) - .addMessageAdapterFactory(TextMessageAdapter.Factory()) - .addMessageAdapterFactory(factory) - .lifecycle(clientLifecycleRegistry) - .build() + .webSocketFactory(webSocketFactory) + .addMessageAdapterFactory(TextMessageAdapter.Factory()) + .addMessageAdapterFactory(factory) + .lifecycle(clientLifecycleRegistry) + .build() return scarlet.create() } private fun blockUntilConnectionIsEstablish() { serverEventObserver.awaitValues( - any>() + any>() ) clientEventObserver.awaitValues( - any>() + any>() ) } - companion object { interface AnInterface { @@ -157,7 +156,6 @@ internal class JacksonMessageAdapterTest { } } - internal interface Service { @Receive fun observeEvents(): Stream @@ -175,5 +173,4 @@ internal class JacksonMessageAdapterTest { fun sendAnInterface(impl: AnInterface): Boolean } } - -} \ No newline at end of file +} From 10b55652d161756b9939d8f65d7165afae87fb5b Mon Sep 17 00:00:00 2001 From: Neil Green Date: Thu, 18 Oct 2018 08:04:01 +0100 Subject: [PATCH 3/7] update README to reflect status of jackson MessageAdapter.Factory --- README.md | 2 +- .../messageadapter/jackson/JacksonMessageAdapterTest.kt | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index bdf09f09..0d1b8677 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ implementation 'com.github.tinder.scarlet:scarlet:$latestVersion' - [x] `moshi` - [x] `gson` - [x] `protobuf` -- [ ] `jackson` +- [x] `jackson` - [ ] `simple-xml` `StreamAdapter.Factory` diff --git a/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt b/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt index 2b24d4da..7b0615e1 100644 --- a/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt +++ b/scarlet-message-adapter-jackson/src/test/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapterTest.kt @@ -160,9 +160,6 @@ internal class JacksonMessageAdapterTest { @Receive fun observeEvents(): Stream - @Send - fun sendString(message: String): Boolean - @Send fun sendAnImplementation(impl: AnImplementation): Boolean From 6f05a9c08628c8f113fcdbb86f699eb5d0c8b443 Mon Sep 17 00:00:00 2001 From: Neil Green Date: Fri, 19 Oct 2018 09:52:27 +0100 Subject: [PATCH 4/7] delete line to force build --- .../scarlet/messageadapter/jackson/JacksonMessageAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt index 362ea812..d07214ad 100644 --- a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt +++ b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt @@ -33,4 +33,4 @@ class JacksonMessageAdapter private constructor( private val DEFAULT_OBJECT_MAPPER = ObjectMapper() } } -} +} \ No newline at end of file From c307082c7e0cd90191bd9957d84d5b6a6d5b4473 Mon Sep 17 00:00:00 2001 From: Neil Green Date: Fri, 19 Oct 2018 12:28:20 +0100 Subject: [PATCH 5/7] add jackson message adapter to jitpack --- publish-jitpack.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/publish-jitpack.sh b/publish-jitpack.sh index 17d1c71e..69824dfa 100755 --- a/publish-jitpack.sh +++ b/publish-jitpack.sh @@ -20,6 +20,8 @@ ./gradlew scarlet-message-adapter-gson:build scarlet-message-adapter-gson:publishToMavenLocal +./gradlew scarlet-message-adapter-gson:build scarlet-message-adapter-jackson:publishToMavenLocal + ./gradlew scarlet-stream-adapter-builtin:build scarlet-stream-adapter-builtin:publishToMavenLocal ./gradlew scarlet-stream-adapter-rxjava2:build scarlet-stream-adapter-rxjava2:publishToMavenLocal From de0a81e86b418a9b778a9773502a439a9fd125cf Mon Sep 17 00:00:00 2001 From: Neil Green Date: Fri, 19 Oct 2018 13:59:57 +0100 Subject: [PATCH 6/7] add jackson message adapter to jitpack - corrected --- publish-jitpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/publish-jitpack.sh b/publish-jitpack.sh index 69824dfa..964036a9 100755 --- a/publish-jitpack.sh +++ b/publish-jitpack.sh @@ -20,7 +20,7 @@ ./gradlew scarlet-message-adapter-gson:build scarlet-message-adapter-gson:publishToMavenLocal -./gradlew scarlet-message-adapter-gson:build scarlet-message-adapter-jackson:publishToMavenLocal +./gradlew scarlet-message-adapter-jackson:build scarlet-message-adapter-jackson:publishToMavenLocal ./gradlew scarlet-stream-adapter-builtin:build scarlet-stream-adapter-builtin:publishToMavenLocal From ea1b91870801294ae80db21ff81430cade1bf32c Mon Sep 17 00:00:00 2001 From: Neil Green Date: Fri, 19 Oct 2018 19:01:09 +0100 Subject: [PATCH 7/7] add line to force build --- .../scarlet/messageadapter/jackson/JacksonMessageAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt index d07214ad..362ea812 100644 --- a/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt +++ b/scarlet-message-adapter-jackson/src/main/java/com/tinder/scarlet/messageadapter/jackson/JacksonMessageAdapter.kt @@ -33,4 +33,4 @@ class JacksonMessageAdapter private constructor( private val DEFAULT_OBJECT_MAPPER = ObjectMapper() } } -} \ No newline at end of file +}