code: private Object invokeRpc(Method method, Object[] args) throws Exception {
  		String methodName = method.getName();
  		Class<?>[] parameterTypes = method.getParameterTypes();
  		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
  		Time futureTimeout = extractRpcTimeout(parameterAnnotations, args, timeout);
  
  		final RpcInvocation rpcInvocation = createRpcInvocationMessage(methodName, parameterTypes, args);
  
  		Class<?> returnType = method.getReturnType();
  
  		final Object result;
  
  		if (Objects.equals(returnType, Void.TYPE)) {
  			tell(rpcInvocation);
  
  			result = null;
  		} else {
  			// execute an asynchronous call
  			CompletableFuture<?> resultFuture = ask(rpcInvocation, futureTimeout);
  
  			CompletableFuture<?> completableFuture = resultFuture.thenApply((Object o) -> {
  				if (o instanceof SerializedValue) {
  					try {
  						return  ((SerializedValue<?>) o).deserializeValue(getClass().getClassLoader());
  					} catch (IOException | ClassNotFoundException e) {
  						throw new CompletionException(
  							new RpcException("Could not deserialize the serialized payload of RPC method : "
  								+ methodName, e));
  					}
  				} else {
  					return o;
  				}
  			});
  
  			if (Objects.equals(returnType, CompletableFuture.class)) {
  				result = completableFuture;
  			} else {
  				try {
  					result = completableFuture.get(futureTimeout.getSize(), futureTimeout.getUnit());
  				} catch (ExecutionException ee) {
  					throw new RpcException("Failure while obtaining synchronous RPC result.", ExceptionUtils.stripExecutionException(ee));
  				}
  			}
  		}
  
  		return result;
  	}
docs: Invokes a RPC method by sending the RPC invocation details to the rpc endpoint.
  
  @param method to call
  @param args of the method call
  @return result of the RPC
  @throws Exception if the RPC invocation fails