Unable to find JsonFormat class in Android · Issue #276 · google/protobuf-gradle-plugin · GitHub
Androidでprotobuf-liteを利用したまま、JSONをオブジェクトにする必要があったので、Gsonで頑張ることにした。InternalなAPIを呼ぶ必要があり困っている。ちなみに grpc/grpc-swiftは頑張る必要もなくシュッと出来ます。
- protoで定義されたフィールドは、生成されたクラスのメンバー変数では最後に
_
がつく- 例えば、
name
というフィールドを持ってるとすると生成されたクラスのメンバー変数ではname_
になる
- 例えば、
- protoで定義されたフィールドでリピートするものは、ただのListではなく
Internal.ProtobufList<T>
で表現されている- TypeAdapter がないとエラーになる
以上をふまえて、以下のようなコードを書いた。
package com.google.protobuf open class ProtobufListTypeAdapter<T>(val parser: (JsonElement) -> Collection<T>): TypeAdapter<Internal.ProtobufList<T>>() { override fun write(out: JsonWriter?, value: Internal.ProtobufList<T>?) { // 利用していないので実装していない } override fun read(jsonReader: JsonReader): Internal.ProtobufList<T> { val list = ProtobufArrayList<T>() list.addAll(parser(JsonParser().parse(jsonReader))) return list } } // 型ごとに作ることになるが、リフレクションで頑張ればどうにかできそう(試していない) class DeliveryTimeListTypeAdapter: ProtobufListTypeAdapter<DeliveryTimeOuterClass.DeliveryTime>({ it.asJsonArray.map { element -> DeliveryTimeOuterClass.DeliveryTime.newBuilder() .build() } })
ProtobufArrayList
が、com.google.protobuf内でしか利用できないので、package com.google.protobuf
にしている。
class ProtoExclusionStrategy: ExclusionStrategy { override fun shouldSkipClass(clazz: Class<*>?): Boolean { return false } override fun shouldSkipField(f: FieldAttributes?): Boolean { if (f == null) { return true } // proto で定義されたフィールド以外は、JSON化しない return !isProtoField(f.name) } fun isProtoField(name: String): Boolean { // filedに _ があると proto で定義されたフィールドとする return name.contains("_") } } val gson = GsonBuilder() .setFieldNamingStrategy { it.name.replace("_", "") } .setExclusionStrategies(ProtoExclusionStrategy()) .registerTypeAdapter( object : TypeToken<Internal.ProtobufList<DeliveryTimeOuterClass.DeliveryTime>>(){}.type, DeliveryTimeListTypeAdapter() ) .create() gson.fromJson(...)
もっといい方法があったら知りたい。