docs: @Override
      public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException {
          final String sourceMethod = "getMBeanInfo";
          checkConnection();
  
          URL mbeanURL = null;
          HttpsURLConnection connection = null;
          try {
              // Get URL for MBean
              mbeanURL = getMBeanURL(name);
  
              // Get connection to server
              connection = getConnection(mbeanURL, HttpMethod.GET);
          } catch (IOException io) {
              throw getRequestErrorException(sourceMethod, io, mbeanURL);
          }
  
          // Check response code from server
          int responseCode = 0;
          try {
              responseCode = connection.getResponseCode();
          } catch (ConnectException ce) {
              recoverConnection(ce);
              // Server is down; not a client bug
              throw ce;
          }
  
          switch (responseCode) {
              case HttpURLConnection.HTTP_OK:
                  JSONConverter converter = JSONConverter.getConverter();
                  try {
                      // Process and return server response, which should be an MBeanInfoWrapper
                      MBeanInfoWrapper wrapper = converter.readMBeanInfo(connection.getInputStream());
                      mbeanAttributesURLMap.put(name, new DynamicURL(connector, wrapper.attributesURL));
  
                      //Attributes
                      Map<String, DynamicURL> attributeURLsMap = mbeanAttributeURLsMap.get(name);
                      final boolean updateAttributes = attributeURLsMap != null;
                      if (!updateAttributes) {
                          // Create a new Map - this map is used for future requests and must be thread safe
                          attributeURLsMap = new ConcurrentHashMap<String, DynamicURL>();
                      }
                      processAttributeOrOperationURLs(attributeURLsMap, wrapper.attributeURLs, updateAttributes);
  
                      if (!updateAttributes) {
                          //Another thread might have created/set this Map already and is about to use it, which is why
                          //we wait until *after* we have a valid Map and are ready to push that in.
                          mbeanAttributeURLsMap.putIfAbsent(name, attributeURLsMap);
                      }
  
                      //Operations
                      Map<String, DynamicURL> operationURLsMap = mbeanOperationURLsMap.get(name);
                      final boolean updateOperations = operationURLsMap != null;
                      if (!updateOperations) {
                          // Create a new Map - this map is used for future requests and must be thread safe
                          operationURLsMap = new ConcurrentHashMap<String, DynamicURL>();
                      }
                      processAttributeOrOperationURLs(operationURLsMap, wrapper.operationURLs, updateOperations);
  
                      if (!updateOperations) {
                          //Another thread might have created/set this Map already and is about to use it, which is why
                          //we wait until *after* we have a valid Map and are ready to push that in.
                          mbeanOperationURLsMap.putIfAbsent(name, operationURLsMap);
                      }
  
                      return wrapper.mbeanInfo;
  
                  } catch (ClassNotFoundException cnf) {
                      // Not a REST connector bug per se; not need to log this case
                      throw new IOException(RESTClientMessagesUtil.getMessage(RESTClientMessagesUtil.SERVER_RESULT_EXCEPTION), cnf);
                  } catch (Exception e) {
                      throw getResponseErrorException(sourceMethod, e, mbeanURL);
                  } finally {
                      JSONConverter.returnConverter(converter);
                  }
              case HttpURLConnection.HTTP_BAD_REQUEST:
              case HttpURLConnection.HTTP_INTERNAL_ERROR:
                  try {
                      // Server response should be a serialized Throwable
                      throw getServerThrowable(sourceMethod, connection);
                  } catch (IntrospectionException ie) {
                      throw ie;
                  } catch (InstanceNotFoundException inf) {
                      throw inf;
                  } catch (ReflectionException re) {
                      throw re;
                  } catch (IOException io) {
                      throw io;
                  } catch (Throwable t) {
                      throw new IOException(RESTClientMessagesUtil.getMessage(RESTClientMessagesUtil.UNEXPECTED_SERVER_THROWABLE), t);
                  }
              case HttpURLConnection.HTTP_UNAUTHORIZED:
              case HttpURLConnection.HTTP_FORBIDDEN:
                  throw getBadCredentialsException(responseCode, connection);
              case HttpURLConnection.HTTP_GONE:
              case HttpURLConnection.HTTP_NOT_FOUND:
                  IOException ioe = getResponseCodeErrorException(sourceMethod, responseCode, connection);
                  recoverConnection(ioe);
                  throw ioe;
              default:
                  throw getResponseCodeErrorException(sourceMethod, responseCode, connection);
          }
      }