private static boolean parseProperty(
      JsonElement propertyElement, IConfigPropertyHolder property, Gson gson) {
    if (!(propertyElement instanceof JsonObject)) return true;

    JsonObject propertyNode = propertyElement.getAsJsonObject();

    JsonElement value = propertyNode.get(VALUE_TAG);

    if (value == null) return true;

    try {
      Object parsedValue = gson.fromJson(value, property.getType());
      property.setValue(parsedValue);
    } catch (Exception e) {
      Log.warn(e, "Failed to parse value of field %s:%s", property.category(), property.name());
      return true;
    }

    JsonElement comment = propertyNode.get(COMMENT_TAG);

    final String expectedComment = property.comment();

    if (comment == null) {
      return !Strings.isNullOrEmpty(expectedComment);
    } else if (comment.isJsonPrimitive()) {
      String commentValue = comment.getAsString();
      return !expectedComment.equals(commentValue);
    }

    return true;
  }
  private static JsonElement dumpConfig(Table<String, String, IConfigPropertyHolder> properties) {
    JsonObject result = new JsonObject();

    Gson gson =
        new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls().create();

    for (Map.Entry<String, Map<String, IConfigPropertyHolder>> category :
        properties.rowMap().entrySet()) {
      JsonObject categoryNode = new JsonObject();

      for (Map.Entry<String, IConfigPropertyHolder> property : category.getValue().entrySet()) {
        JsonObject propertyNode = new JsonObject();

        IConfigPropertyHolder propertyHolder = property.getValue();

        final String comment = propertyHolder.comment();
        if (!Strings.isNullOrEmpty(comment)) propertyNode.addProperty(COMMENT_TAG, comment);

        try {
          Object value = propertyHolder.getValue();
          JsonElement serialized = gson.toJsonTree(value);
          propertyNode.add(VALUE_TAG, serialized);
        } catch (Exception e) {
          Log.warn(
              e,
              "Failed to serialize property %s:%s",
              propertyHolder.category(),
              propertyHolder.name());
        }

        categoryNode.add(property.getKey(), propertyNode);
      }

      result.add(category.getKey(), categoryNode);
    }

    return result;
  }