Search code examples
javalistgrpcgrpc-java

How to override a gRPC list method for implementation in a Java service


I have the following schema in my messages.proto file:

message Person {
  string id = 1;
  string first_name = 2;
  string last_name = 3;
  string email = 4;
  string alias = 5;
}

//CREATE, DELETE, UPDATE RESPONSES AND REQUESTS Messages

message ListPersonsRequest {
    ListOptions options = 1;
}

message ListPersonsResponse {
   repeated Person person = 1;
   string total_count = 2;
   string total_pages = 3;
   string next_page_token = 4;
}

I have the following schema in my services.proto file:

service PersonService {

  //rpc methods to create, update, delete...

  rpc ListPersons (ListPersonsRequest) returns  (ListPersonsResponse) {
    option (google.api.http) = {
      get: "/person"
    };
  }
}

In my class 'ServiceImp':

@GrpcService
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class PersonServiceImpl extends PersonServiceImplBase
{

   private PersonRepository personRepository;

   @Override
   public void getPerson(GetPersonRequest request, StreamObserver<GetPersonResponse> responseObserver)
   {

      try
      {
         Person person = personRepository.findById(UUID.fromString(request.getId())).orElseThrow(() -> new EntityNotFoundException());

         Person personProto = Person
             .newBuilder()
             .setId(person.getId().toString())
             .setFirstName(person.getFirstName())
               .setLastName(person.getLastName())
               .setEmail(person.getEmail())
               .setAlias(person.getAlias()).build();

         GetPersonResponse response = GetPersonResponse.newBuilder().setPerson(personProto).build();

         responseObserver.onNext(response);
         responseObserver.onCompleted();
      }
      catch (EntityNotFoundException e)
      {
         responseObserver.onError(Status.NOT_FOUND.withCause(e).asException());
      }

   }

   @Override
   public void createPerson(CreatePersonRequest request, StreamObserver<CreatePersonResponse> responseObserver)
   {
      Person person = Person.builder().firstName(request.getPerson().getFirstName()).lastName(request.getPerson().getLastName()).email(request.getPerson().getEmail()).alias(request.getPerson().getAlias())
            .build();
      person = personRepository.save(person); // probably should handle errors

      Person personProto = Person.newBuilder().setId(person.getId().toString()).setFirstName(person.getFirstName())
            .setLastName(person.getLastName()).setEmail(person.getEmail()).setAlias(person.getAlias()).build();

      CreatePersonResponse response = CreatePersonResponse.newBuilder().setPerson(personProto).build();

      responseObserver.onNext(response);
      responseObserver.onCompleted();
   }

   @Override
   public void listPersons(ListPersonsRequest request, StreamObserver<ListPersonsResponse> responseObserver){

   }
}

I'm trying to response a object which contains a list of all the created items, but I'm confused with how to implement it in my listPerson method, that I'm overriding from the created serviceGRPC

private static volatile io.grpc.MethodDescriptor<grpc.generated.ListPersonsRequest,
    grpc.generated.ListPersonsResponse> getListPersonsMethod;

@io.grpc.stub.annotations.RpcMethod(
    fullMethodName = SERVICE_NAME + '/' + "ListPersons",
    requestType = grpc.generated.ListPersonsRequest.class,
    responseType = grpc.generated.ListPersonsResponse.class,
    methodType = io.grpc.MethodDescriptor.MethodType.UNARY)
public static io.grpc.MethodDescriptor<grpc.generated.ListPersonsRequest,
    grpc.generated.ListPersonsResponse> getListPersonsMethod() {
  io.grpc.MethodDescriptor<grpc.generated.ListPersonsRequest, grpc.generated.ListPersonsResponse> getListPersonsMethod;
  if ((getListPersonsMethod = PersonServiceGrpc.getListPersonsMethod) == null) {
    synchronized (PersonServiceGrpc.class) {
      if ((getListPersonsMethod = PersonServiceGrpc.getListPersonsMethod) == null) {
        PersonServiceGrpc.getListPersonsMethod = getListPersonsMethod =
            io.grpc.MethodDescriptor.<grpc.generated.ListPersonsRequest, grpc.generated.ListPersonsResponse>newBuilder()
            .setType(io.grpc.MethodDescriptor.MethodType.UNARY)
            .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListPersons"))
            .setSampledToLocalTracing(true)
            .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
                grpc.generated.ListPersonsRequest.getDefaultInstance()))
            .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
                grpc.generated.ListPersonsResponse.getDefaultInstance()))
            .setSchemaDescriptor(new PersonServiceMethodDescriptorSupplier("ListPersons"))
            .build();
      }
    }
  }
  return getListPersonsMethod;
}
@Override
public void listPersons(ListPersonsRequest request, StreamObserver<ListPersonsResponse> responseObserver){
    //Heres were implement is cofused
}

I know that using a stream you are returning an iterator and that means you can start processing the Items on client even before the server has finished the gRPC response, but I'm using the entire object. Is there a way to return it with the stored values? How?


Solution

  • You don't need to do any streaming here. All you need to do is return your result by calling responseObserver.onNext(myListPersonsResponse) after constructing the response object.