From 62967314c144214d2df76e1c71641e4be190f5a4 Mon Sep 17 00:00:00 2001 From: Harold Martin Date: Wed, 2 Jun 2021 12:03:42 -0700 Subject: [PATCH] Update Protobuf support (#2381) Summary: **Update protobuf library with new support for `enum` and `oneof` types** ## Changelog - Update plugin code for library API changes and other cleanup - Add instructions to readme Pull Request resolved: https://github.com/facebook/flipper/pull/2381 Test Plan: see demo app at https://github.com/hbmartin/protobuf_java_to_protobufjs Reviewed By: priteshrnandgaonkar Differential Revision: D28831035 Pulled By: passy fbshipit-source-id: 46e196293330b615394606bd3486ea47ad6a0630 --- .../plugins/retrofit2-protobuf/build.gradle | 2 +- .../SendProtobufToFlipperFromRetrofit.kt | 23 +++++++++--------- ...finitionsToMessageDefinitionsIfProtobuf.kt | 4 ++-- ...RetrofitServiceToGenericCallDefinitions.kt | 4 ++-- .../model/CallNestedMessagesPayload.kt | 24 ++++++++++++------- .../model/FullNamedMessagesCallDefinition.kt | 6 ++--- docs/setup/network-plugin.mdx | 19 +++++++++++++++ 7 files changed, 53 insertions(+), 29 deletions(-) diff --git a/android/plugins/retrofit2-protobuf/build.gradle b/android/plugins/retrofit2-protobuf/build.gradle index db04759c1..92accde03 100644 --- a/android/plugins/retrofit2-protobuf/build.gradle +++ b/android/plugins/retrofit2-protobuf/build.gradle @@ -25,7 +25,7 @@ android { implementation project(':network-plugin') implementation deps.protobuf implementation "com.squareup.retrofit2:retrofit:2.9.0" - implementation "com.github.hbmartin:protobuf_java_to_protobufjs:0.0.1" + implementation "com.github.hbmartin:protobuf_java_to_protobufjs:0.1.0" compileOnly deps.jsr305 } } diff --git a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/SendProtobufToFlipperFromRetrofit.kt b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/SendProtobufToFlipperFromRetrofit.kt index db827dc01..24fd4f93d 100644 --- a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/SendProtobufToFlipperFromRetrofit.kt +++ b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/SendProtobufToFlipperFromRetrofit.kt @@ -9,24 +9,23 @@ package com.facebook.flipper.plugins.retrofit2protobuf import com.facebook.flipper.android.AndroidFlipperClient import com.facebook.flipper.core.FlipperArray -import com.facebook.flipper.core.FlipperObject import com.facebook.flipper.core.FlipperValue import com.facebook.flipper.plugins.network.NetworkFlipperPlugin import com.facebook.flipper.plugins.retrofit2protobuf.adapter.GenericCallDefinitionsToMessageDefinitionsIfProtobuf import com.facebook.flipper.plugins.retrofit2protobuf.adapter.RetrofitServiceToGenericCallDefinitions import com.facebook.flipper.plugins.retrofit2protobuf.model.CallNestedMessagesPayload -import me.haroldmartin.protobufjavatoprotobufjs.adapter.FullNamedMessagesToNestedMessages object SendProtobufToFlipperFromRetrofit { operator fun invoke(baseUrl: String, service: Class<*>) { - AndroidFlipperClient.getInstanceIfInitialized()?.let { client -> - (client.getPlugin(NetworkFlipperPlugin.ID) as? NetworkFlipperPlugin) - ?.send( - "addProtobufDefinitions", - FlipperObject.Builder().put( - baseUrl, generateProtobufDefinitions(service).toFlipperArray() - ).build() - ) + getNetworkPlugin()?.addProtobufDefinitions( + baseUrl, + generateProtobufDefinitions(service).toFlipperArray() + ) + } + + private fun getNetworkPlugin(): NetworkFlipperPlugin? { + return AndroidFlipperClient.getInstanceIfInitialized()?.let { client -> + client.getPlugin(NetworkFlipperPlugin.ID) as? NetworkFlipperPlugin } } @@ -39,9 +38,9 @@ object SendProtobufToFlipperFromRetrofit { path = it.path, method = it.method, requestMessageFullName = it.requestMessageFullName, - requestDefinitions = FullNamedMessagesToNestedMessages(it.requestModel), + requestDefinitions = it.requestModel, responseMessageFullName = it.responseMessageFullName, - responseDefinitions = FullNamedMessagesToNestedMessages(it.responseModel) + responseDefinitions = it.responseModel ) } } diff --git a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/GenericCallDefinitionsToMessageDefinitionsIfProtobuf.kt b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/GenericCallDefinitionsToMessageDefinitionsIfProtobuf.kt index d3eb67328..57e29ac26 100644 --- a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/GenericCallDefinitionsToMessageDefinitionsIfProtobuf.kt +++ b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/GenericCallDefinitionsToMessageDefinitionsIfProtobuf.kt @@ -25,9 +25,9 @@ internal object GenericCallDefinitionsToMessageDefinitionsIfProtobuf { path = definition.path, method = definition.method, responseMessageFullName = responseRootAndMessages?.rootFullName, - responseModel = responseRootAndMessages?.messages, + responseModel = responseRootAndMessages?.descriptors, requestMessageFullName = requestRootAndMessages?.rootFullName, - requestModel = requestRootAndMessages?.messages + requestModel = requestRootAndMessages?.descriptors ) } } diff --git a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/RetrofitServiceToGenericCallDefinitions.kt b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/RetrofitServiceToGenericCallDefinitions.kt index a0e863128..6075704cc 100644 --- a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/RetrofitServiceToGenericCallDefinitions.kt +++ b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/adapter/RetrofitServiceToGenericCallDefinitions.kt @@ -53,8 +53,8 @@ private val Array.urlPathAndMethod: Pair? private val Method.requestBodyType: Class<*>? get() { - parameterAnnotations.forEachIndexed { index, parameters -> - parameters.forEach { annotation -> + parameterAnnotations.forEachIndexed { index, annotations -> + annotations.forEach { annotation -> if (annotation.annotationClass == retrofit2.http.Body::class) { return parameterTypes[index] } diff --git a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/CallNestedMessagesPayload.kt b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/CallNestedMessagesPayload.kt index ef8c5a57d..a97879c8a 100644 --- a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/CallNestedMessagesPayload.kt +++ b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/CallNestedMessagesPayload.kt @@ -7,6 +7,7 @@ package com.facebook.flipper.plugins.retrofit2protobuf.model +import com.facebook.flipper.core.FlipperArray import com.facebook.flipper.core.FlipperObject import com.facebook.flipper.core.FlipperValue @@ -14,29 +15,34 @@ internal data class CallNestedMessagesPayload( val path: String, val method: String, val requestMessageFullName: String?, - val requestDefinitions: Map, + val requestDefinitions: Map?, val responseMessageFullName: String?, - val responseDefinitions: Map + val responseDefinitions: Map? ) : FlipperValue { override fun toFlipperObject(): FlipperObject { return FlipperObject.Builder() .put("path", path) .put("method", method) .put("requestMessageFullName", requestMessageFullName) - .put("requestDefinitions", requestDefinitions.toFlipperObject()) + .put("requestDefinitions", requestDefinitions?.toFlipperObject()) .put("responseMessageFullName", responseMessageFullName) - .put("responseDefinitions", responseDefinitions.toFlipperObject()) + .put("responseDefinitions", responseDefinitions?.toFlipperObject()) .build() } } private fun Map<*, *>.toFlipperObject(): FlipperObject { val builder = FlipperObject.Builder() - this.forEach { - builder.put( - it.key as String, - if (it.value is Map<*, *>) (it.value as Map<*, *>).toFlipperObject() else it.value - ) + this.forEach { (key, value) -> + val castValue = when (value) { + is Map<*, *> -> value.toFlipperObject() + is Iterable<*> -> value.toFlipperArray() + else -> value + } + builder.put(key as String, castValue) } return builder.build() } + +private fun Iterable<*>.toFlipperArray(): FlipperArray = + fold(FlipperArray.Builder()) { builder, value -> builder.put(value as? String) }.build() diff --git a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/FullNamedMessagesCallDefinition.kt b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/FullNamedMessagesCallDefinition.kt index 239e524ae..38216f71a 100644 --- a/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/FullNamedMessagesCallDefinition.kt +++ b/android/plugins/retrofit2-protobuf/src/main/java/com/facebook/flipper/plugins/retrofit2protobuf/model/FullNamedMessagesCallDefinition.kt @@ -7,13 +7,13 @@ package com.facebook.flipper.plugins.retrofit2protobuf.model -import me.haroldmartin.protobufjavatoprotobufjs.model.FullNamedMessages +import me.haroldmartin.protobufjavatoprotobufjs.adapter.JsDescriptors internal data class FullNamedMessagesCallDefinition( val path: String, val method: String, val requestMessageFullName: String?, val responseMessageFullName: String?, - val responseModel: FullNamedMessages?, - val requestModel: FullNamedMessages? + val responseModel: JsDescriptors?, + val requestModel: JsDescriptors? ) diff --git a/docs/setup/network-plugin.mdx b/docs/setup/network-plugin.mdx index cd0969d8e..b26d72cd3 100644 --- a/docs/setup/network-plugin.mdx +++ b/docs/setup/network-plugin.mdx @@ -49,6 +49,25 @@ new OkHttpClient.Builder() As interceptors can modify the request and response, add the Flipper interceptor after all others to get an accurate view of the network traffic. +### Protobuf / Retrofit Integration + +If you are using Retrofit with Protobuf request or response types, you can setup automatic decoding so that the network inspector can display a human readable payload. First you must add the separate dependency: + +```groovy +dependencies { + debugImplementation 'com.facebook.flipper:flipper-retrofit2-protobuf-plugin:0.91.2' +} +``` + +Then call `SendProtobufToFlipperFromRetrofit` for each service class. + +```kotlin +import com.facebook.flipper.plugins.retrofit2protobuf.SendProtobufToFlipperFromRetrofit + +SendProtobufToFlipperFromRetrofit("https://baseurl.com/", MyApiService::class.java) +``` + + ## iOS To enable network inspection, add the following pod to your Podfile: