KotlinでgRPCを使ったときのことをまとめてみた

この記事は [MicroAd Advent Calendar 2020](https://qiita.com/advent-calendar/2020/microad "MicroAd Advent Calendar 2020") の1日目の記事です。

（余談ですが、qiita初投稿です。）

# はじめに

とある案件で、gRPCを使うことになりました。

「◯◯◯APIを画面から呼び出して情報を取得して画面に表示する」的な話の流れだったので、何も知らなかった僕はHTTP的なものをイメージしていました。

ところが、色々と調べていくうちに、全然違うもので、実装方法もまるで別物ということが分かり、こりゃヤバイ、ということで色々調べつつ実装していた記憶があります。

この記事では、その時に得た知見などを書いて行きたいと思います。

※主にgRPCを呼び出すクライアント側の実装のお話です。

# gRPC とは
他の記事によくまとまっていたので引用させていただきます。
> gRPCはGoogle謹製のHTTP/2を利用したRPCフレームワークです。
Protocol Buffersを利用し、データをシリアライズして高速なRPCを実現します。

> protoファイルと呼ばれるIDL(Interface Definition Language)にAPI仕様を記述します。
また、IDLからサーバーサイドとクライアントサイドの雛形コードを自動生成できます。
自動生成コードは多言語対応で、サーバーサイドとクライアンサイドが異なる言語でも問題ありません。

> RPCはRemote Procedure Callの略です。
バラしてみるとこんな感じです。

> Remote = リモートサーバの。
Procedure = 手続き（メソッド）を。
Call = 呼び出す（実行する）。

> つまり、「ローカルのメソッドを実行するのと同じような感覚でリモートサーバのメソッドを実行」できます。
gRPC以外にもJSON-RPCなどが有名です。
REST-APIのようにパスやメソッドなどを指定する必要がありません。単に関数と引数を指定するだけです。
REST-APIの替わりとして注目を集めています。

引用：https://qiita.com/gold-kou/items/a1cc2be6045723e242eb

# gRPCを使うには
大まかにまとめると以下の4点です

- インターフェースが定義されたprotoファイルを作る
  - [公式のサンプルコード](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto "公式のサンプルコード")だと、src/main/proto/の下に作られている
- protoファイルからコードを自動生成するための設定を追加する
  - mavenならpom.xml（[公式のサンプルコード](https://github.com/grpc/grpc-java/blob/master/examples/pom.xml "公式のサンプルコード")）
  - gradleならbuild.gradle（[公式のサンプルコード](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle "公式のサンプルコード")）
- コードを自動生成する
  - ビルドすると自動生成される（コードの自動生成だけすることもできる）
  - target/generated-sources/protobuf/ の下に生成されたコードができる
  - コンパイル時に、この場所も見てくれるらしい
- 自動生成されたコードに記載されているメソッドを呼び出す
  - 他に必要な情報としては、呼び出し先サーバのhost、port
  - プロキシを経由したい場合、若干工夫が必要

### インターフェースが定義されたprotoファイルを作る

```proto:src/main/proto/xxx_yyy_zzz.proto
syntax = "proto3";
import "google/protobuf/timestamp.proto";

package jp.aaa.bbb.ccc;

message HugaHugaRequest {
  int32 hugaHugaParam = 1;
}

message HugaHugaReply {
  string hugaHugaReturn = 1;
}

service HogeHogeService {
  rpc HugaHugaMethod (HugaHugaRequest) returns (HugaHugaReply) {}
}
```

### protoファイルからコードを自動生成するための設定を追加する
pom.xmlに追加した設定を記載します。（ほぼ公式サンプルのとおりです）
※gradleはやっていませんのでご了承ください。

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <properties>
        <grpc.version>1.31.0</grpc.version>
        <protobuf.version>3.12.4</protobuf.version>
        <protoc.version>3.12.4</protoc.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- https://github.com/grpc/grpc-java -->
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-bom</artifactId>
                <version>${grpc.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- https://github.com/grpc/grpc-java -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>${protobuf.version}</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
        </dependency>
    </dependencies>

    <build>
        <!-- protocコマンドのダウンロードに必要 -->
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.6.2</version>
            </extension>
        </extensions>

        <plugins>
            <!-- protoファイルからコードを自動生成するための設定 -->
            <!-- target/generated-sources/protobuf/ 以下にコードが生成される -->
            <!-- https://github.com/grpc/grpc-java -->
            <!-- https://www.xolstice.org/protobuf-maven-plugin/ -->
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
```

### コードを自動生成する
プロジェクト全体をビルドすればコードが自動生成されます。
下記の2つのコマンドを実行することでも、コードを自動生成できます。

``` 自動生成コマンド.txt
mvn protobuf:compile
mvn protobuf:compile-custom
```

<details><summary>自動生成コード① jp/aaa/bbb/ccc/HogeHogeServiceGrpc.java（289行）</summary><div>


```target/generated-sources/protobuf/grpc-java/jp/aaa/bbb/ccc/HogeHogeServiceGrpc.java
package jp.aaa.bbb.ccc;

import static io.grpc.MethodDescriptor.generateFullMethodName;
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
import static io.grpc.stub.ClientCalls.futureUnaryCall;
import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;

/**
 */
@javax.annotation.Generated(
    value = "by gRPC proto compiler (version 1.31.0)",
    comments = "Source: xxx_yyy_zzz.proto")
public final class HogeHogeServiceGrpc {

  private HogeHogeServiceGrpc() {}

  public static final String SERVICE_NAME = "jp.aaa.bbb.ccc.HogeHogeService";

  // Static method descriptors that strictly reflect the proto.
  private static volatile io.grpc.MethodDescriptor<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest,
      jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply> getHugaHugaMethodMethod;

  @io.grpc.stub.annotations.RpcMethod(
      fullMethodName = SERVICE_NAME + '/' + "HugaHugaMethod",
      requestType = jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.class,
      responseType = jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.class,
      methodType = io.grpc.MethodDescriptor.MethodType.UNARY)
  public static io.grpc.MethodDescriptor<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest,
      jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply> getHugaHugaMethodMethod() {
    io.grpc.MethodDescriptor<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest, jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply> getHugaHugaMethodMethod;
    if ((getHugaHugaMethodMethod = HogeHogeServiceGrpc.getHugaHugaMethodMethod) == null) {
      synchronized (HogeHogeServiceGrpc.class) {
        if ((getHugaHugaMethodMethod = HogeHogeServiceGrpc.getHugaHugaMethodMethod) == null) {
          HogeHogeServiceGrpc.getHugaHugaMethodMethod = getHugaHugaMethodMethod =
              io.grpc.MethodDescriptor.<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest, jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply>newBuilder()
              .setType(io.grpc.MethodDescriptor.MethodType.UNARY)
              .setFullMethodName(generateFullMethodName(SERVICE_NAME, "HugaHugaMethod"))
              .setSampledToLocalTracing(true)
              .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
                  jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.getDefaultInstance()))
              .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
                  jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.getDefaultInstance()))
              .setSchemaDescriptor(new HogeHogeServiceMethodDescriptorSupplier("HugaHugaMethod"))
              .build();
        }
      }
    }
    return getHugaHugaMethodMethod;
  }

  /**
   * Creates a new async stub that supports all call types for the service
   */
  public static HogeHogeServiceStub newStub(io.grpc.Channel channel) {
    io.grpc.stub.AbstractStub.StubFactory<HogeHogeServiceStub> factory =
      new io.grpc.stub.AbstractStub.StubFactory<HogeHogeServiceStub>() {
        @java.lang.Override
        public HogeHogeServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
          return new HogeHogeServiceStub(channel, callOptions);
        }
      };
    return HogeHogeServiceStub.newStub(factory, channel);
  }

  /**
   * Creates a new blocking-style stub that supports unary and streaming output calls on the service
   */
  public static HogeHogeServiceBlockingStub newBlockingStub(
      io.grpc.Channel channel) {
    io.grpc.stub.AbstractStub.StubFactory<HogeHogeServiceBlockingStub> factory =
      new io.grpc.stub.AbstractStub.StubFactory<HogeHogeServiceBlockingStub>() {
        @java.lang.Override
        public HogeHogeServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
          return new HogeHogeServiceBlockingStub(channel, callOptions);
        }
      };
    return HogeHogeServiceBlockingStub.newStub(factory, channel);
  }

  /**
   * Creates a new ListenableFuture-style stub that supports unary calls on the service
   */
  public static HogeHogeServiceFutureStub newFutureStub(
      io.grpc.Channel channel) {
    io.grpc.stub.AbstractStub.StubFactory<HogeHogeServiceFutureStub> factory =
      new io.grpc.stub.AbstractStub.StubFactory<HogeHogeServiceFutureStub>() {
        @java.lang.Override
        public HogeHogeServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
          return new HogeHogeServiceFutureStub(channel, callOptions);
        }
      };
    return HogeHogeServiceFutureStub.newStub(factory, channel);
  }

  /**
   */
  public static abstract class HogeHogeServiceImplBase implements io.grpc.BindableService {

    /**
     */
    public void hugaHugaMethod(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest request,
        io.grpc.stub.StreamObserver<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply> responseObserver) {
      asyncUnimplementedUnaryCall(getHugaHugaMethodMethod(), responseObserver);
    }

    @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() {
      return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
          .addMethod(
            getHugaHugaMethodMethod(),
            asyncUnaryCall(
              new MethodHandlers<
                jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest,
                jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply>(
                  this, METHODID_HUGA_HUGA_METHOD)))
          .build();
    }
  }

  /**
   */
  public static final class HogeHogeServiceStub extends io.grpc.stub.AbstractAsyncStub<HogeHogeServiceStub> {
    private HogeHogeServiceStub(
        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
      super(channel, callOptions);
    }

    @java.lang.Override
    protected HogeHogeServiceStub build(
        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
      return new HogeHogeServiceStub(channel, callOptions);
    }

    /**
     */
    public void hugaHugaMethod(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest request,
        io.grpc.stub.StreamObserver<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply> responseObserver) {
      asyncUnaryCall(
          getChannel().newCall(getHugaHugaMethodMethod(), getCallOptions()), request, responseObserver);
    }
  }

  /**
   */
  public static final class HogeHogeServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub<HogeHogeServiceBlockingStub> {
    private HogeHogeServiceBlockingStub(
        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
      super(channel, callOptions);
    }

    @java.lang.Override
    protected HogeHogeServiceBlockingStub build(
        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
      return new HogeHogeServiceBlockingStub(channel, callOptions);
    }

    /**
     */
    public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply hugaHugaMethod(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest request) {
      return blockingUnaryCall(
          getChannel(), getHugaHugaMethodMethod(), getCallOptions(), request);
    }
  }

  /**
   */
  public static final class HogeHogeServiceFutureStub extends io.grpc.stub.AbstractFutureStub<HogeHogeServiceFutureStub> {
    private HogeHogeServiceFutureStub(
        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
      super(channel, callOptions);
    }

    @java.lang.Override
    protected HogeHogeServiceFutureStub build(
        io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
      return new HogeHogeServiceFutureStub(channel, callOptions);
    }

    /**
     */
    public com.google.common.util.concurrent.ListenableFuture<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply> hugaHugaMethod(
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest request) {
      return futureUnaryCall(
          getChannel().newCall(getHugaHugaMethodMethod(), getCallOptions()), request);
    }
  }

  private static final int METHODID_HUGA_HUGA_METHOD = 0;

  private static final class MethodHandlers<Req, Resp> implements
      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
    private final HogeHogeServiceImplBase serviceImpl;
    private final int methodId;

    MethodHandlers(HogeHogeServiceImplBase serviceImpl, int methodId) {
      this.serviceImpl = serviceImpl;
      this.methodId = methodId;
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("unchecked")
    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
      switch (methodId) {
        case METHODID_HUGA_HUGA_METHOD:
          serviceImpl.hugaHugaMethod((jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest) request,
              (io.grpc.stub.StreamObserver<jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply>) responseObserver);
          break;
        default:
          throw new AssertionError();
      }
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("unchecked")
    public io.grpc.stub.StreamObserver<Req> invoke(
        io.grpc.stub.StreamObserver<Resp> responseObserver) {
      switch (methodId) {
        default:
          throw new AssertionError();
      }
    }
  }

  private static abstract class HogeHogeServiceBaseDescriptorSupplier
      implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier {
    HogeHogeServiceBaseDescriptorSupplier() {}

    @java.lang.Override
    public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {
      return jp.aaa.bbb.ccc.XxxYyyZzz.getDescriptor();
    }

    @java.lang.Override
    public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {
      return getFileDescriptor().findServiceByName("HogeHogeService");
    }
  }

  private static final class HogeHogeServiceFileDescriptorSupplier
      extends HogeHogeServiceBaseDescriptorSupplier {
    HogeHogeServiceFileDescriptorSupplier() {}
  }

  private static final class HogeHogeServiceMethodDescriptorSupplier
      extends HogeHogeServiceBaseDescriptorSupplier
      implements io.grpc.protobuf.ProtoMethodDescriptorSupplier {
    private final String methodName;

    HogeHogeServiceMethodDescriptorSupplier(String methodName) {
      this.methodName = methodName;
    }

    @java.lang.Override
    public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {
      return getServiceDescriptor().findMethodByName(methodName);
    }
  }

  private static volatile io.grpc.ServiceDescriptor serviceDescriptor;

  public static io.grpc.ServiceDescriptor getServiceDescriptor() {
    io.grpc.ServiceDescriptor result = serviceDescriptor;
    if (result == null) {
      synchronized (HogeHogeServiceGrpc.class) {
        result = serviceDescriptor;
        if (result == null) {
          serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME)
              .setSchemaDescriptor(new HogeHogeServiceFileDescriptorSupplier())
              .addMethod(getHugaHugaMethodMethod())
              .build();
        }
      }
    }
    return result;
  }
}

```

</div></details>


<details><summary>自動生成コード② jp/aaa/bbb/ccc/XxxYyyZzz.java（1122行）</summary><div>


```target/generated-sources/protobuf/java/jp/aaa/bbb/ccc/XxxYyyZzz.java
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: xxx_yyy_zzz.proto

package jp.aaa.bbb.ccc;

public final class XxxYyyZzz {
  private XxxYyyZzz() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }

  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  public interface HugaHugaRequestOrBuilder extends
      // @@protoc_insertion_point(interface_extends:jp.aaa.bbb.ccc.HugaHugaRequest)
      com.google.protobuf.MessageOrBuilder {

    /**
     * <code>int32 hugaHugaParam = 1;</code>
     * @return The hugaHugaParam.
     */
    int getHugaHugaParam();
  }
  /**
   * Protobuf type {@code jp.aaa.bbb.ccc.HugaHugaRequest}
   */
  public static final class HugaHugaRequest extends
      com.google.protobuf.GeneratedMessageV3 implements
      // @@protoc_insertion_point(message_implements:jp.aaa.bbb.ccc.HugaHugaRequest)
      HugaHugaRequestOrBuilder {
  private static final long serialVersionUID = 0L;
    // Use HugaHugaRequest.newBuilder() to construct.
    private HugaHugaRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
      super(builder);
    }
    private HugaHugaRequest() {
    }

    @java.lang.Override
    @SuppressWarnings({"unused"})
    protected java.lang.Object newInstance(
        UnusedPrivateParameter unused) {
      return new HugaHugaRequest();
    }

    @java.lang.Override
    public final com.google.protobuf.UnknownFieldSet
    getUnknownFields() {
      return this.unknownFields;
    }
    private HugaHugaRequest(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      this();
      if (extensionRegistry == null) {
        throw new java.lang.NullPointerException();
      }
      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
          com.google.protobuf.UnknownFieldSet.newBuilder();
      try {
        boolean done = false;
        while (!done) {
          int tag = input.readTag();
          switch (tag) {
            case 0:
              done = true;
              break;
            case 8: {

              hugaHugaParam_ = input.readInt32();
              break;
            }
            default: {
              if (!parseUnknownField(
                  input, unknownFields, extensionRegistry, tag)) {
                done = true;
              }
              break;
            }
          }
        }
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        throw e.setUnfinishedMessage(this);
      } catch (java.io.IOException e) {
        throw new com.google.protobuf.InvalidProtocolBufferException(
            e).setUnfinishedMessage(this);
      } finally {
        this.unknownFields = unknownFields.build();
        makeExtensionsImmutable();
      }
    }
    public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
      return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_descriptor;
    }

    @java.lang.Override
    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
        internalGetFieldAccessorTable() {
      return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.class, jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.Builder.class);
    }

    public static final int HUGAHUGAPARAM_FIELD_NUMBER = 1;
    private int hugaHugaParam_;
    /**
     * <code>int32 hugaHugaParam = 1;</code>
     * @return The hugaHugaParam.
     */
    @java.lang.Override
    public int getHugaHugaParam() {
      return hugaHugaParam_;
    }

    private byte memoizedIsInitialized = -1;
    @java.lang.Override
    public final boolean isInitialized() {
      byte isInitialized = memoizedIsInitialized;
      if (isInitialized == 1) return true;
      if (isInitialized == 0) return false;

      memoizedIsInitialized = 1;
      return true;
    }

    @java.lang.Override
    public void writeTo(com.google.protobuf.CodedOutputStream output)
                        throws java.io.IOException {
      if (hugaHugaParam_ != 0) {
        output.writeInt32(1, hugaHugaParam_);
      }
      unknownFields.writeTo(output);
    }

    @java.lang.Override
    public int getSerializedSize() {
      int size = memoizedSize;
      if (size != -1) return size;

      size = 0;
      if (hugaHugaParam_ != 0) {
        size += com.google.protobuf.CodedOutputStream
          .computeInt32Size(1, hugaHugaParam_);
      }
      size += unknownFields.getSerializedSize();
      memoizedSize = size;
      return size;
    }

    @java.lang.Override
    public boolean equals(final java.lang.Object obj) {
      if (obj == this) {
       return true;
      }
      if (!(obj instanceof jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest)) {
        return super.equals(obj);
      }
      jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest other = (jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest) obj;

      if (getHugaHugaParam()
          != other.getHugaHugaParam()) return false;
      if (!unknownFields.equals(other.unknownFields)) return false;
      return true;
    }

    @java.lang.Override
    public int hashCode() {
      if (memoizedHashCode != 0) {
        return memoizedHashCode;
      }
      int hash = 41;
      hash = (19 * hash) + getDescriptor().hashCode();
      hash = (37 * hash) + HUGAHUGAPARAM_FIELD_NUMBER;
      hash = (53 * hash) + getHugaHugaParam();
      hash = (29 * hash) + unknownFields.hashCode();
      memoizedHashCode = hash;
      return hash;
    }

    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        java.nio.ByteBuffer data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        java.nio.ByteBuffer data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        com.google.protobuf.ByteString data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        com.google.protobuf.ByteString data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(byte[] data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        byte[] data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(java.io.InputStream input)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        java.io.InputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseDelimitedFrom(java.io.InputStream input)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseDelimitedWithIOException(PARSER, input);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseDelimitedFrom(
        java.io.InputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        com.google.protobuf.CodedInputStream input)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parseFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input, extensionRegistry);
    }

    @java.lang.Override
    public Builder newBuilderForType() { return newBuilder(); }
    public static Builder newBuilder() {
      return DEFAULT_INSTANCE.toBuilder();
    }
    public static Builder newBuilder(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest prototype) {
      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
    }
    @java.lang.Override
    public Builder toBuilder() {
      return this == DEFAULT_INSTANCE
          ? new Builder() : new Builder().mergeFrom(this);
    }

    @java.lang.Override
    protected Builder newBuilderForType(
        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
      Builder builder = new Builder(parent);
      return builder;
    }
    /**
     * Protobuf type {@code jp.aaa.bbb.ccc.HugaHugaRequest}
     */
    public static final class Builder extends
        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
        // @@protoc_insertion_point(builder_implements:jp.aaa.bbb.ccc.HugaHugaRequest)
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequestOrBuilder {
      public static final com.google.protobuf.Descriptors.Descriptor
          getDescriptor() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_descriptor;
      }

      @java.lang.Override
      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
          internalGetFieldAccessorTable() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_fieldAccessorTable
            .ensureFieldAccessorsInitialized(
                jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.class, jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.Builder.class);
      }

      // Construct using jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.newBuilder()
      private Builder() {
        maybeForceBuilderInitialization();
      }

      private Builder(
          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
        super(parent);
        maybeForceBuilderInitialization();
      }
      private void maybeForceBuilderInitialization() {
        if (com.google.protobuf.GeneratedMessageV3
                .alwaysUseFieldBuilders) {
        }
      }
      @java.lang.Override
      public Builder clear() {
        super.clear();
        hugaHugaParam_ = 0;

        return this;
      }

      @java.lang.Override
      public com.google.protobuf.Descriptors.Descriptor
          getDescriptorForType() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_descriptor;
      }

      @java.lang.Override
      public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest getDefaultInstanceForType() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.getDefaultInstance();
      }

      @java.lang.Override
      public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest build() {
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest result = buildPartial();
        if (!result.isInitialized()) {
          throw newUninitializedMessageException(result);
        }
        return result;
      }

      @java.lang.Override
      public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest buildPartial() {
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest result = new jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest(this);
        result.hugaHugaParam_ = hugaHugaParam_;
        onBuilt();
        return result;
      }

      @java.lang.Override
      public Builder clone() {
        return super.clone();
      }
      @java.lang.Override
      public Builder setField(
          com.google.protobuf.Descriptors.FieldDescriptor field,
          java.lang.Object value) {
        return super.setField(field, value);
      }
      @java.lang.Override
      public Builder clearField(
          com.google.protobuf.Descriptors.FieldDescriptor field) {
        return super.clearField(field);
      }
      @java.lang.Override
      public Builder clearOneof(
          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
        return super.clearOneof(oneof);
      }
      @java.lang.Override
      public Builder setRepeatedField(
          com.google.protobuf.Descriptors.FieldDescriptor field,
          int index, java.lang.Object value) {
        return super.setRepeatedField(field, index, value);
      }
      @java.lang.Override
      public Builder addRepeatedField(
          com.google.protobuf.Descriptors.FieldDescriptor field,
          java.lang.Object value) {
        return super.addRepeatedField(field, value);
      }
      @java.lang.Override
      public Builder mergeFrom(com.google.protobuf.Message other) {
        if (other instanceof jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest) {
          return mergeFrom((jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest)other);
        } else {
          super.mergeFrom(other);
          return this;
        }
      }

      public Builder mergeFrom(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest other) {
        if (other == jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest.getDefaultInstance()) return this;
        if (other.getHugaHugaParam() != 0) {
          setHugaHugaParam(other.getHugaHugaParam());
        }
        this.mergeUnknownFields(other.unknownFields);
        onChanged();
        return this;
      }

      @java.lang.Override
      public final boolean isInitialized() {
        return true;
      }

      @java.lang.Override
      public Builder mergeFrom(
          com.google.protobuf.CodedInputStream input,
          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
          throws java.io.IOException {
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest parsedMessage = null;
        try {
          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
          parsedMessage = (jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest) e.getUnfinishedMessage();
          throw e.unwrapIOException();
        } finally {
          if (parsedMessage != null) {
            mergeFrom(parsedMessage);
          }
        }
        return this;
      }

      private int hugaHugaParam_ ;
      /**
       * <code>int32 hugaHugaParam = 1;</code>
       * @return The hugaHugaParam.
       */
      @java.lang.Override
      public int getHugaHugaParam() {
        return hugaHugaParam_;
      }
      /**
       * <code>int32 hugaHugaParam = 1;</code>
       * @param value The hugaHugaParam to set.
       * @return This builder for chaining.
       */
      public Builder setHugaHugaParam(int value) {
        
        hugaHugaParam_ = value;
        onChanged();
        return this;
      }
      /**
       * <code>int32 hugaHugaParam = 1;</code>
       * @return This builder for chaining.
       */
      public Builder clearHugaHugaParam() {
        
        hugaHugaParam_ = 0;
        onChanged();
        return this;
      }
      @java.lang.Override
      public final Builder setUnknownFields(
          final com.google.protobuf.UnknownFieldSet unknownFields) {
        return super.setUnknownFields(unknownFields);
      }

      @java.lang.Override
      public final Builder mergeUnknownFields(
          final com.google.protobuf.UnknownFieldSet unknownFields) {
        return super.mergeUnknownFields(unknownFields);
      }


      // @@protoc_insertion_point(builder_scope:jp.aaa.bbb.ccc.HugaHugaRequest)
    }

    // @@protoc_insertion_point(class_scope:jp.aaa.bbb.ccc.HugaHugaRequest)
    private static final jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest DEFAULT_INSTANCE;
    static {
      DEFAULT_INSTANCE = new jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest();
    }

    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest getDefaultInstance() {
      return DEFAULT_INSTANCE;
    }

    private static final com.google.protobuf.Parser<HugaHugaRequest>
        PARSER = new com.google.protobuf.AbstractParser<HugaHugaRequest>() {
      @java.lang.Override
      public HugaHugaRequest parsePartialFrom(
          com.google.protobuf.CodedInputStream input,
          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
          throws com.google.protobuf.InvalidProtocolBufferException {
        return new HugaHugaRequest(input, extensionRegistry);
      }
    };

    public static com.google.protobuf.Parser<HugaHugaRequest> parser() {
      return PARSER;
    }

    @java.lang.Override
    public com.google.protobuf.Parser<HugaHugaRequest> getParserForType() {
      return PARSER;
    }

    @java.lang.Override
    public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaRequest getDefaultInstanceForType() {
      return DEFAULT_INSTANCE;
    }

  }

  public interface HugaHugaReplyOrBuilder extends
      // @@protoc_insertion_point(interface_extends:jp.aaa.bbb.ccc.HugaHugaReply)
      com.google.protobuf.MessageOrBuilder {

    /**
     * <code>string hugaHugaReturn = 1;</code>
     * @return The hugaHugaReturn.
     */
    java.lang.String getHugaHugaReturn();
    /**
     * <code>string hugaHugaReturn = 1;</code>
     * @return The bytes for hugaHugaReturn.
     */
    com.google.protobuf.ByteString
        getHugaHugaReturnBytes();
  }
  /**
   * Protobuf type {@code jp.aaa.bbb.ccc.HugaHugaReply}
   */
  public static final class HugaHugaReply extends
      com.google.protobuf.GeneratedMessageV3 implements
      // @@protoc_insertion_point(message_implements:jp.aaa.bbb.ccc.HugaHugaReply)
      HugaHugaReplyOrBuilder {
  private static final long serialVersionUID = 0L;
    // Use HugaHugaReply.newBuilder() to construct.
    private HugaHugaReply(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
      super(builder);
    }
    private HugaHugaReply() {
      hugaHugaReturn_ = "";
    }

    @java.lang.Override
    @SuppressWarnings({"unused"})
    protected java.lang.Object newInstance(
        UnusedPrivateParameter unused) {
      return new HugaHugaReply();
    }

    @java.lang.Override
    public final com.google.protobuf.UnknownFieldSet
    getUnknownFields() {
      return this.unknownFields;
    }
    private HugaHugaReply(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      this();
      if (extensionRegistry == null) {
        throw new java.lang.NullPointerException();
      }
      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
          com.google.protobuf.UnknownFieldSet.newBuilder();
      try {
        boolean done = false;
        while (!done) {
          int tag = input.readTag();
          switch (tag) {
            case 0:
              done = true;
              break;
            case 10: {
              java.lang.String s = input.readStringRequireUtf8();

              hugaHugaReturn_ = s;
              break;
            }
            default: {
              if (!parseUnknownField(
                  input, unknownFields, extensionRegistry, tag)) {
                done = true;
              }
              break;
            }
          }
        }
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        throw e.setUnfinishedMessage(this);
      } catch (java.io.IOException e) {
        throw new com.google.protobuf.InvalidProtocolBufferException(
            e).setUnfinishedMessage(this);
      } finally {
        this.unknownFields = unknownFields.build();
        makeExtensionsImmutable();
      }
    }
    public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
      return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaReply_descriptor;
    }

    @java.lang.Override
    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
        internalGetFieldAccessorTable() {
      return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaReply_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.class, jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.Builder.class);
    }

    public static final int HUGAHUGARETURN_FIELD_NUMBER = 1;
    private volatile java.lang.Object hugaHugaReturn_;
    /**
     * <code>string hugaHugaReturn = 1;</code>
     * @return The hugaHugaReturn.
     */
    @java.lang.Override
    public java.lang.String getHugaHugaReturn() {
      java.lang.Object ref = hugaHugaReturn_;
      if (ref instanceof java.lang.String) {
        return (java.lang.String) ref;
      } else {
        com.google.protobuf.ByteString bs = 
            (com.google.protobuf.ByteString) ref;
        java.lang.String s = bs.toStringUtf8();
        hugaHugaReturn_ = s;
        return s;
      }
    }
    /**
     * <code>string hugaHugaReturn = 1;</code>
     * @return The bytes for hugaHugaReturn.
     */
    @java.lang.Override
    public com.google.protobuf.ByteString
        getHugaHugaReturnBytes() {
      java.lang.Object ref = hugaHugaReturn_;
      if (ref instanceof java.lang.String) {
        com.google.protobuf.ByteString b = 
            com.google.protobuf.ByteString.copyFromUtf8(
                (java.lang.String) ref);
        hugaHugaReturn_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }

    private byte memoizedIsInitialized = -1;
    @java.lang.Override
    public final boolean isInitialized() {
      byte isInitialized = memoizedIsInitialized;
      if (isInitialized == 1) return true;
      if (isInitialized == 0) return false;

      memoizedIsInitialized = 1;
      return true;
    }

    @java.lang.Override
    public void writeTo(com.google.protobuf.CodedOutputStream output)
                        throws java.io.IOException {
      if (!getHugaHugaReturnBytes().isEmpty()) {
        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, hugaHugaReturn_);
      }
      unknownFields.writeTo(output);
    }

    @java.lang.Override
    public int getSerializedSize() {
      int size = memoizedSize;
      if (size != -1) return size;

      size = 0;
      if (!getHugaHugaReturnBytes().isEmpty()) {
        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, hugaHugaReturn_);
      }
      size += unknownFields.getSerializedSize();
      memoizedSize = size;
      return size;
    }

    @java.lang.Override
    public boolean equals(final java.lang.Object obj) {
      if (obj == this) {
       return true;
      }
      if (!(obj instanceof jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply)) {
        return super.equals(obj);
      }
      jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply other = (jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply) obj;

      if (!getHugaHugaReturn()
          .equals(other.getHugaHugaReturn())) return false;
      if (!unknownFields.equals(other.unknownFields)) return false;
      return true;
    }

    @java.lang.Override
    public int hashCode() {
      if (memoizedHashCode != 0) {
        return memoizedHashCode;
      }
      int hash = 41;
      hash = (19 * hash) + getDescriptor().hashCode();
      hash = (37 * hash) + HUGAHUGARETURN_FIELD_NUMBER;
      hash = (53 * hash) + getHugaHugaReturn().hashCode();
      hash = (29 * hash) + unknownFields.hashCode();
      memoizedHashCode = hash;
      return hash;
    }

    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        java.nio.ByteBuffer data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        java.nio.ByteBuffer data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        com.google.protobuf.ByteString data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        com.google.protobuf.ByteString data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(byte[] data)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        byte[] data,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(java.io.InputStream input)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        java.io.InputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseDelimitedFrom(java.io.InputStream input)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseDelimitedWithIOException(PARSER, input);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseDelimitedFrom(
        java.io.InputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        com.google.protobuf.CodedInputStream input)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input);
    }
    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parseFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      return com.google.protobuf.GeneratedMessageV3
          .parseWithIOException(PARSER, input, extensionRegistry);
    }

    @java.lang.Override
    public Builder newBuilderForType() { return newBuilder(); }
    public static Builder newBuilder() {
      return DEFAULT_INSTANCE.toBuilder();
    }
    public static Builder newBuilder(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply prototype) {
      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
    }
    @java.lang.Override
    public Builder toBuilder() {
      return this == DEFAULT_INSTANCE
          ? new Builder() : new Builder().mergeFrom(this);
    }

    @java.lang.Override
    protected Builder newBuilderForType(
        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
      Builder builder = new Builder(parent);
      return builder;
    }
    /**
     * Protobuf type {@code jp.aaa.bbb.ccc.HugaHugaReply}
     */
    public static final class Builder extends
        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
        // @@protoc_insertion_point(builder_implements:jp.aaa.bbb.ccc.HugaHugaReply)
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReplyOrBuilder {
      public static final com.google.protobuf.Descriptors.Descriptor
          getDescriptor() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaReply_descriptor;
      }

      @java.lang.Override
      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
          internalGetFieldAccessorTable() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaReply_fieldAccessorTable
            .ensureFieldAccessorsInitialized(
                jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.class, jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.Builder.class);
      }

      // Construct using jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.newBuilder()
      private Builder() {
        maybeForceBuilderInitialization();
      }

      private Builder(
          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
        super(parent);
        maybeForceBuilderInitialization();
      }
      private void maybeForceBuilderInitialization() {
        if (com.google.protobuf.GeneratedMessageV3
                .alwaysUseFieldBuilders) {
        }
      }
      @java.lang.Override
      public Builder clear() {
        super.clear();
        hugaHugaReturn_ = "";

        return this;
      }

      @java.lang.Override
      public com.google.protobuf.Descriptors.Descriptor
          getDescriptorForType() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.internal_static_jp_aaa_bbb_ccc_HugaHugaReply_descriptor;
      }

      @java.lang.Override
      public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply getDefaultInstanceForType() {
        return jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.getDefaultInstance();
      }

      @java.lang.Override
      public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply build() {
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply result = buildPartial();
        if (!result.isInitialized()) {
          throw newUninitializedMessageException(result);
        }
        return result;
      }

      @java.lang.Override
      public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply buildPartial() {
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply result = new jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply(this);
        result.hugaHugaReturn_ = hugaHugaReturn_;
        onBuilt();
        return result;
      }

      @java.lang.Override
      public Builder clone() {
        return super.clone();
      }
      @java.lang.Override
      public Builder setField(
          com.google.protobuf.Descriptors.FieldDescriptor field,
          java.lang.Object value) {
        return super.setField(field, value);
      }
      @java.lang.Override
      public Builder clearField(
          com.google.protobuf.Descriptors.FieldDescriptor field) {
        return super.clearField(field);
      }
      @java.lang.Override
      public Builder clearOneof(
          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
        return super.clearOneof(oneof);
      }
      @java.lang.Override
      public Builder setRepeatedField(
          com.google.protobuf.Descriptors.FieldDescriptor field,
          int index, java.lang.Object value) {
        return super.setRepeatedField(field, index, value);
      }
      @java.lang.Override
      public Builder addRepeatedField(
          com.google.protobuf.Descriptors.FieldDescriptor field,
          java.lang.Object value) {
        return super.addRepeatedField(field, value);
      }
      @java.lang.Override
      public Builder mergeFrom(com.google.protobuf.Message other) {
        if (other instanceof jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply) {
          return mergeFrom((jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply)other);
        } else {
          super.mergeFrom(other);
          return this;
        }
      }

      public Builder mergeFrom(jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply other) {
        if (other == jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply.getDefaultInstance()) return this;
        if (!other.getHugaHugaReturn().isEmpty()) {
          hugaHugaReturn_ = other.hugaHugaReturn_;
          onChanged();
        }
        this.mergeUnknownFields(other.unknownFields);
        onChanged();
        return this;
      }

      @java.lang.Override
      public final boolean isInitialized() {
        return true;
      }

      @java.lang.Override
      public Builder mergeFrom(
          com.google.protobuf.CodedInputStream input,
          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
          throws java.io.IOException {
        jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply parsedMessage = null;
        try {
          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
          parsedMessage = (jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply) e.getUnfinishedMessage();
          throw e.unwrapIOException();
        } finally {
          if (parsedMessage != null) {
            mergeFrom(parsedMessage);
          }
        }
        return this;
      }

      private java.lang.Object hugaHugaReturn_ = "";
      /**
       * <code>string hugaHugaReturn = 1;</code>
       * @return The hugaHugaReturn.
       */
      public java.lang.String getHugaHugaReturn() {
        java.lang.Object ref = hugaHugaReturn_;
        if (!(ref instanceof java.lang.String)) {
          com.google.protobuf.ByteString bs =
              (com.google.protobuf.ByteString) ref;
          java.lang.String s = bs.toStringUtf8();
          hugaHugaReturn_ = s;
          return s;
        } else {
          return (java.lang.String) ref;
        }
      }
      /**
       * <code>string hugaHugaReturn = 1;</code>
       * @return The bytes for hugaHugaReturn.
       */
      public com.google.protobuf.ByteString
          getHugaHugaReturnBytes() {
        java.lang.Object ref = hugaHugaReturn_;
        if (ref instanceof String) {
          com.google.protobuf.ByteString b = 
              com.google.protobuf.ByteString.copyFromUtf8(
                  (java.lang.String) ref);
          hugaHugaReturn_ = b;
          return b;
        } else {
          return (com.google.protobuf.ByteString) ref;
        }
      }
      /**
       * <code>string hugaHugaReturn = 1;</code>
       * @param value The hugaHugaReturn to set.
       * @return This builder for chaining.
       */
      public Builder setHugaHugaReturn(
          java.lang.String value) {
        if (value == null) {
    throw new NullPointerException();
  }
  
        hugaHugaReturn_ = value;
        onChanged();
        return this;
      }
      /**
       * <code>string hugaHugaReturn = 1;</code>
       * @return This builder for chaining.
       */
      public Builder clearHugaHugaReturn() {
        
        hugaHugaReturn_ = getDefaultInstance().getHugaHugaReturn();
        onChanged();
        return this;
      }
      /**
       * <code>string hugaHugaReturn = 1;</code>
       * @param value The bytes for hugaHugaReturn to set.
       * @return This builder for chaining.
       */
      public Builder setHugaHugaReturnBytes(
          com.google.protobuf.ByteString value) {
        if (value == null) {
    throw new NullPointerException();
  }
  checkByteStringIsUtf8(value);
        
        hugaHugaReturn_ = value;
        onChanged();
        return this;
      }
      @java.lang.Override
      public final Builder setUnknownFields(
          final com.google.protobuf.UnknownFieldSet unknownFields) {
        return super.setUnknownFields(unknownFields);
      }

      @java.lang.Override
      public final Builder mergeUnknownFields(
          final com.google.protobuf.UnknownFieldSet unknownFields) {
        return super.mergeUnknownFields(unknownFields);
      }


      // @@protoc_insertion_point(builder_scope:jp.aaa.bbb.ccc.HugaHugaReply)
    }

    // @@protoc_insertion_point(class_scope:jp.aaa.bbb.ccc.HugaHugaReply)
    private static final jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply DEFAULT_INSTANCE;
    static {
      DEFAULT_INSTANCE = new jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply();
    }

    public static jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply getDefaultInstance() {
      return DEFAULT_INSTANCE;
    }

    private static final com.google.protobuf.Parser<HugaHugaReply>
        PARSER = new com.google.protobuf.AbstractParser<HugaHugaReply>() {
      @java.lang.Override
      public HugaHugaReply parsePartialFrom(
          com.google.protobuf.CodedInputStream input,
          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
          throws com.google.protobuf.InvalidProtocolBufferException {
        return new HugaHugaReply(input, extensionRegistry);
      }
    };

    public static com.google.protobuf.Parser<HugaHugaReply> parser() {
      return PARSER;
    }

    @java.lang.Override
    public com.google.protobuf.Parser<HugaHugaReply> getParserForType() {
      return PARSER;
    }

    @java.lang.Override
    public jp.aaa.bbb.ccc.XxxYyyZzz.HugaHugaReply getDefaultInstanceForType() {
      return DEFAULT_INSTANCE;
    }

  }

  private static final com.google.protobuf.Descriptors.Descriptor
    internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_descriptor;
  private static final 
    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
      internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_fieldAccessorTable;
  private static final com.google.protobuf.Descriptors.Descriptor
    internal_static_jp_aaa_bbb_ccc_HugaHugaReply_descriptor;
  private static final 
    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
      internal_static_jp_aaa_bbb_ccc_HugaHugaReply_fieldAccessorTable;

  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static  com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    java.lang.String[] descriptorData = {
      "\n\021xxx_yyy_zzz.proto\022\016jp.aaa.bbb.ccc\032\037goo" +
      "gle/protobuf/timestamp.proto\"(\n\017HugaHuga" +
      "Request\022\025\n\rhugaHugaParam\030\001 \001(\005\"\'\n\rHugaHu" +
      "gaReply\022\026\n\016hugaHugaReturn\030\001 \001(\t2e\n\017HogeH" +
      "ogeService\022R\n\016HugaHugaMethod\022\037.jp.aaa.bb" +
      "b.ccc.HugaHugaRequest\032\035.jp.aaa.bbb.ccc.H" +
      "ugaHugaReply\"\000b\006proto3"
    };
    descriptor = com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
          com.google.protobuf.TimestampProto.getDescriptor(),
        });
    internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_descriptor =
      getDescriptor().getMessageTypes().get(0);
    internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
        internal_static_jp_aaa_bbb_ccc_HugaHugaRequest_descriptor,
        new java.lang.String[] { "HugaHugaParam", });
    internal_static_jp_aaa_bbb_ccc_HugaHugaReply_descriptor =
      getDescriptor().getMessageTypes().get(1);
    internal_static_jp_aaa_bbb_ccc_HugaHugaReply_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
        internal_static_jp_aaa_bbb_ccc_HugaHugaReply_descriptor,
        new java.lang.String[] { "HugaHugaReturn", });
    com.google.protobuf.TimestampProto.getDescriptor();
  }

  // @@protoc_insertion_point(outer_class_scope)
}

```

</div></details>

自動生成されたコードは、ボリュームが大きいので、どのようにコード管理するかは要検討かと思います。

- git管理する
- git管理せず、protoファイルからコード生成する形でやっていく
- 自動生成されたコードをjarファイルにまとめて、そのjarファイルを依存に加える

など。

この記事用に、限りなくシンプルな定義ファイルにしたつもりなのですが、それでも1000行超えました。
実際の案件では10000行を超えてきます。

ちなみに自動生成コードのファイル名とパッケージですが、下記のようになっているようです。

- 自動生成コードのパッケージ：protoファイルに記載されているpackage
- 自動生成コード①のファイル名：protoファイルに記載されているservice + Grpc
- 自動生成コード②のファイル名：protoファイルのファイル名をキャメルケースにしたもの（xxx_yyy_zzz.proto）

### 自動生成されたコードに記載されているメソッドを呼び出す

- Stubインスタンスを生成（下記の例では、シングルトンオブジェクトにしています。）
- 生成したStubから、メソッドを呼び出す

※パッケージやimportはだいぶ省略させて頂いております。

##### Stubインスタンスを生成

```HogeHogeApiConfiguration.kt
import jp.aaa.bbb.ccc.HogeHogeServiceGrpc

/*
 * APIの接続設定
 * VPNプロキシ設定はリモート環境で社内のサーバーと通信する場合のみ必要
 */
@Component
class HogeHogeApiConfiguration(
        private val proxyHost: String = "proxyhost",
        private val proxyPort: Int = 8888,
        private val timeout: Int = 5000,
        private val hogeHogeApiHost: String = "hogehogehost",
        private val hogeHogeApiPort: Int = 9999
) {
    @Bean(name = ["HogeHogeApiStub"])
    fun createHogeHogeApiStub(): HogeHogeServiceGrpc.HogeHogeServiceBlockingStub {
        val isReachable = InetAddress.getByName(hogeHogeApiHost).isReachable(timeout)
        val channel = ManagedChannelBuilder
                .forAddress(hogeHogeApiHost, hogeHogeApiPort)
                .usePlaintext()
                .apply { if (!isReachable) proxyDetector(createProxyDetector()) }
                .build()
        return HogeHogeServiceGrpc.newBlockingStub(channel)
    }

    private fun createProxyDetector(): ProxyDetector {
        return ProxyDetector { targetServerAddress ->
            HttpConnectProxiedSocketAddress.newBuilder()
                    .setTargetAddress(targetServerAddress as InetSocketAddress)
                    .setProxyAddress(InetSocketAddress(proxyHost, proxyPort))
                    .build()
        }
    }
}
```

##### 生成したStubから、メソッドを呼び出す

```HogeHogeDaoImpl.kt
import jp.aaa.bbb.ccc.HogeHogeServiceGrpc
import jp.aaa.bbb.ccc.XxxYyyZzz

@Component
internal class HogeHogeDaoImpl(
        @Qualifier("HogeHogeApiStub")
        private val apiStub: HogeHogeServiceGrpc.HogeHogeServiceBlockingStub
) : HogeHogeDao {
    override fun callHugaHugaMethod(): String {
        // Request
        val request: XxxYyyZzz.HugaHugaRequest =
                XxxYyyZzz.HugaHugaRequest.newBuilder().setHugaHugaParam(99).build()

        // call hugaHugaMethod()
        val reply: XxxYyyZzz.HugaHugaReply = apiStub.hugaHugaMethod(request)

        return reply.hugaHugaReturn
    }
}
```

# 終わりに

昨今のコロナ事情で、リモートワーク環境でgRPCを使えるようにする件がほぼ必須となり、createProxyDetector の部分を頑張って実装していたのが良い思い出です。

全体的に、Kotlinの師匠であるM氏にはレビューなどで大変お世話になりました。

この記事が様々な人の役に立てば幸いです。