docs: static List<JmxData> query(MBeanServer server, ObjectName query) throws Exception {
      List<JmxData> data = new ArrayList<>();
  
      Set<ObjectName> names = server.queryNames(query, null);
      LOGGER.trace("query [{}], found {} matches", query, names.size());
      for (ObjectName name : names) {
        MBeanInfo info = server.getMBeanInfo(name);
        MBeanAttributeInfo[] attrs = info.getAttributes();
        String[] attrNames = new String[attrs.length];
        for (int i = 0; i < attrs.length; ++i) {
          attrNames[i] = attrs[i].getName();
        }
  
        Map<String, String> stringAttrs = new HashMap<>();
        stringAttrs.put("domain", name.getDomain());
        Map<String, Number> numberAttrs = new HashMap<>();
  
        for (Attribute attr : server.getAttributes(name, attrNames).asList()) {
          Object obj = attr.getValue();
          if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("attribute [{}][{}] = {}", name, attr.getName(), mkString(obj));
          }
  
          if (obj instanceof String) {
            stringAttrs.put(attr.getName(), (String) obj);
          } else if (obj instanceof Number) {
            numberAttrs.put(attr.getName(), ((Number) obj).doubleValue());
          } else if (obj instanceof CompositeDataSupport) {
            CompositeDataSupport composite = (CompositeDataSupport) obj;
            CompositeType compositeType = composite.getCompositeType();
            for (String key : compositeType.keySet()) {
              if (composite.containsKey(key)) {
                Object o = composite.get(key);
                String attrKey = attr.getName() + "." + key;
                if (o instanceof Number) {
                  numberAttrs.put(attrKey, ((Number) o).doubleValue());
                } else if (o instanceof String) {
                  stringAttrs.put(attrKey, (String) o);
                } else if (o instanceof TimeUnit) {
                  stringAttrs.put(attrKey, o.toString());
                }
              }
            }
          } else if (obj instanceof TimeUnit) {
            stringAttrs.put(attr.getName(), obj.toString());
          }
        }
  
        // Add properties from ObjectName after attributes to ensure they have a higher
        // priority if the same key is used both in the Object and as an attribute
        stringAttrs.putAll(name.getKeyPropertyList());
  
        data.add(new JmxData(name, stringAttrs, numberAttrs));
      }
  
      return data;
    }