code: public final boolean refreshToken() throws IOException {
      lock.lock();
      try {
        try {
          TokenResponse tokenResponse = executeRefreshToken();
          if (tokenResponse != null) {
            setFromTokenResponse(tokenResponse);
            for (CredentialRefreshListener refreshListener : refreshListeners) {
              refreshListener.onTokenResponse(this, tokenResponse);
            }
            return true;
          }
        } catch (TokenResponseException e) {
          boolean statusCode4xx = 400 <= e.getStatusCode() && e.getStatusCode() < 500;
          // check if it is a normal error response
          if (e.getDetails() != null && statusCode4xx) {
            // We were unable to get a new access token (e.g. it may have been revoked), we must now
            // indicate that our current token is invalid.
            setAccessToken(null);
            setExpiresInSeconds(null);
          }
          for (CredentialRefreshListener refreshListener : refreshListeners) {
            refreshListener.onTokenErrorResponse(this, e.getDetails());
          }
          if (statusCode4xx) {
            throw e;
          }
        }
        return false;
      } finally {
        lock.unlock();
      }
    }
docs: Request a new access token from the authorization endpoint.
  
  <p>
  On success, it will call {@link #setFromTokenResponse(TokenResponse)}, call
  {@link CredentialRefreshListener#onTokenResponse} with the token response, and return
  {@code true}. On error, it will call {@link #setAccessToken(String)} and
  {@link #setExpiresInSeconds(Long)} with {@code null}, call
  {@link CredentialRefreshListener#onTokenErrorResponse} with the token error response, and
  return {@code false}. If a 4xx error is encountered while refreshing the token,
  {@link TokenResponseException} is thrown.
  </p>
  
  <p>
  If there is no refresh token, it will quietly return {@code false}.
  </p>
  
  @return whether a new access token was successfully retrieved