MavenでGoogleAdsAPIを使用する実行可能Jarを作成するときに気を付けること

# 記事を書くに至ったきっかけ
タイトルの通りのことをやろうとした時に、あるエラーがなかなか解決できず（2022/04/27時点）、Mavenの設定やらで少し調べることになったので、備忘録も兼ねて記事を書くことにしました。

# 問題になったエラー
``` Command
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の設定

該当する設定部分を以下に記述します。

``` xml: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は問題なく使用できると思います。
備忘録として利用してくださるとうれしいです。