記事を書くに至ったきっかけ
タイトルの通りのことをやろうとした時に、あるエラーがなかなか解決できず(2022/04/27時点)、Mavenの設定やらで少し調べることになったので、備忘録も兼ねて記事を書くことにしました。
問題になったエラー
io.grpc.internal.ManagedChannelImpl$2 uncaughtException
重大: [Channel<1>: (googleads.googleapis.com:443)] Uncaught exception in the SynchronizationContext. Panic!
java.lang.IllegalStateException: Could not find policy 'pick_first'.
Make sure its implementation is either registered to LoadBalancerRegistry or included in META-INF/services/io.grpc.LoadBalancerProvider from your jar files.
MavenプロジェクトにGoogleAdsAPIとその依存関係をimportするだけではエラーが起き、そのエラーはどうやらgRPC絡みのようです。
ちなみに、gRPCはGoogleが開発したプロトコルであり、GoogleのAPIではデフォルトでこのプロトコルが使われるように実装されています。
gRPCが用いるデータ通信方式である「Protocol Buffers」はRESTよりも高速な通信を実現できるため、最近よくgRPCが使われているらしいです。
対応
1. 使用するプラグインについて
Mavenで依存ライブラリを含んだ実行可能Jarを作る場合は、
- Maven-Assembly-plugin
- Maven-Shade-Plugin
のいずれかを使うことになります。
たぶんどちらを使っても行けると思いますが、今回私は後者を使ったので、後者のプラグインでJarを作成する前提でいきます。
2. pom.xmlの設定
該当する設定部分を以下に記述します。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <!-- 1 -->
<!-- <finalName>${project.name}</finalName> -->
<transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer"> <!-- 2 -->
<resource>META-INF/services</resource>
<file>io.grpc.LoadBalancerProvider</file>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>META-INF/services</resource>
<file>io.grpc.NameResolverProvider</file>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <!-- 3 -->
<manifestEntries>
<Main-Class>com.example.App</Main-Class>
</manifestEntries>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
具体的に問題になるのは「Configuration」の中と「filters」の中です。
3.Configurationについて
Transformerの設定が必要になります。
-
1について
このオプションをきじゅつすることで、META-INF/services/配下にあるService Loaderによりロードするファイルをマージするようになります。 -
2について
このオプションでは、指定したリソースを追加することができます。
この記述をすれば動く、という解決策は、Githubのissueで報告されていました。(参考URL:https://github.com/googleapis/google-cloud-java/issues/4700)
io.grpc.LoadBalancerProvider
とio.grpc.NameResolverProvider
を追加する設定を自分で書かないといけないようです。 -
3について
メインクラスを指定しないと動かないので、このオプションで指定しましょう。
4. filtersについて
上記のpom.xmlに記述されている形式のファイルは不要で、この設定を書き忘れてもエラーが出るので、忘れないようにしましょう。
なんでexcludeしないといけないのかは忘れてしまったので、どなたか教えてください。
最後に
以上の設定を行えば、Mavenプロジェクト上でgRPCを使用するAPIは問題なく使用できると思います。
備忘録として利用してくださるとうれしいです。