Search Tutorials


Spring Boot + gRPC Error Handling - Global Exception Handler Using GrpcAdvice | JavaInUse

Spring Boot + gRPC Error Handling - Global Exception Handler Using GrpcAdvice

In previous tutorial we implemented Spring Boot + gRPC Error Handling - Using Trailer Metadata. In this tutorial we will be implementing global exception handler for the spring boot gRPC server. By using @GrpcAdvice, we can define a class with methods that handle certain types of exceptions, providing a centralized way to manage and customize error handling in your application.
Spring Boot 3 global exception handler Using GrpcAdvice

Video

This tutorial is explained in the below Youtube Video.

gRPC - Table of Contents

Spring Boot+ gRPC Hello World Example Spring Boot gRPC Server + C# gRPC Client Example Spring Boot 3 + gRPC - Types of gRPC Spring Boot 3 + gRPC Unary Example Spring Boot 3 + gRPC Server Streaming Example Spring Boot 3 + gRPC Client Streaming Example Spring Boot 3 + gRPC Bidirectional Streaming Example Spring Boot + gRPC Deadline Example Spring Boot + gRPC Error Handling Example Spring Boot + gRPC Error Handling - Using Trailer Metadata Spring Boot + gRPC Error Handling - Global Exception Handler Using GrpcAdvice

Implementation

We will be modifying the code we had implemented for Spring Boot gRPC Error Handling Example - Using Trailer Metadata.
We create a custom exception handler class named BankAccountAdvice. The BankAccountAdvice class is annotated with @GrpcAdvice which indicates that this class provides advice to the gRPC server for handling exceptions.
The handleAccountNotFoundException method is annotated with @GrpcExceptionHandler for handling the AccountNotFoundException specifically. Within this method, a Metadata object is created to attach additional metadata to the response. A key for a protocol buffer message type DatabaseError is created using ProtoUtils.keyForProto method. This DatabaseError message is then added to the metadata with a customized error message indicating a database error with a specific error type. Finally, a StatusRuntimeException is created with the HTTP status code NOT_FOUND and a description indicating that the requested account number cannot be found. The metadata containing the DatabaseError message is attached to the StatusRuntimeException and returned from the method to inform the client about the error that occurred.
package com.javainuse.bank.service;

import com.javainuse.bank.exception.AccountNotFoundException;
import com.javainuse.banking.DatabaseError;

import io.grpc.Metadata;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.protobuf.ProtoUtils;
import net.devh.boot.grpc.server.advice.GrpcAdvice;
import net.devh.boot.grpc.server.advice.GrpcExceptionHandler;

@GrpcAdvice
public class BankAccountAdvice {

	@GrpcExceptionHandler(AccountNotFoundException.class)
	public StatusRuntimeException handleAccountNotFoundException(AccountNotFoundException accountNotFoundException) {
		Metadata metadata = new Metadata();
		Metadata.Key<DatabaseError> databaseError = ProtoUtils.keyForProto(DatabaseError.getDefaultInstance());
		metadata.put(databaseError, DatabaseError.newBuilder().setMessage("Database Error- Connection Refused.")
				.setErrorType("CONNECTION_REFUSED").build());
		var statusRuntimeException = Status.NOT_FOUND.withDescription("The requested Account Number cannot be found.")
				.asRuntimeException(metadata);
		return statusRuntimeException;
	}
}





Next we modify the BankAccountBalanceService to throw a new AccountNotFoundException instead of implementing the error handling code.
package com.javainuse.bank.service;

import com.javainuse.bank.exception.AccountNotFoundException;
import com.javainuse.banking.AccountBalanceResponse;
import com.javainuse.banking.AccountBalanceServiceGrpc;
import com.javainuse.banking.AccountRequest;

import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;

@GrpcService
public class BankAccountBalanceService extends AccountBalanceServiceGrpc.AccountBalanceServiceImplBase {

	@Override
	public void getAccountBalance(AccountRequest request,
			StreamObserver<com.javainuse.banking.AccountBalanceResponse> responseObserver) {

		if ((request.getAccountNumber().equals("account5"))) {
			throw new AccountNotFoundException("Database Error- Connection Refused.");
		}
		AccountBalanceResponse empResp = AccountBalanceResponse.newBuilder()
				.setAccountNumber(request.getAccountNumber()).setBalance(100).build();

		// set the response object
		responseObserver.onNext(empResp);

		// mark process is completed
		responseObserver.onCompleted();
	}
}
Start the gRPC server and also the client.
Spring Boot 3 + gRPC error handling custom code

Download Source Code

Download it - Spring Boot + gRPC Advice Example
Download it - Spring Boot + gRPC Advice Example