docs: protected JsonValue toJsonInternal(Object object, boolean ignoreNullValuedProperties) {
      if (object == null) {
        return Json.NULL;
      }
  
      if (object instanceof JsonValue) {
        return (JsonValue) object;
      }
  
      if (object instanceof List<?>) {
        JsonArray jsonArray = new JsonArray();
        for (Object o : (List<?>) object)
          jsonArray.add(toJsonInternal(o, ignoreNullValuedProperties));
  
        return jsonArray;
      }
  
      if (object instanceof Map<?, ?>) {
        JsonObject jsonObject = new JsonObject();
        for (Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
          if (!(entry.getKey() instanceof String)) {
            throw new FacebookJsonMappingException("Your Map keys must be of type " + String.class
                + " in order to be converted to JSON.  Offending map is " + object);
          }
  
          try {
            jsonObject.add((String) entry.getKey(), toJsonInternal(entry.getValue(), ignoreNullValuedProperties));
          } catch (ParseException | IllegalArgumentException e) {
            throw new FacebookJsonMappingException(
              "Unable to process value '" + entry.getValue() + "' for key '" + entry.getKey() + "' in Map " + object, e);
          }
        }
  
        return jsonObject;
      }
  
      if (isPrimitive(object)) {
        return primitiveToJsonValue(object);
      }
  
      if (object instanceof BigInteger) {
        return Json.value(((BigInteger) object).longValue());
      }
  
      if (object instanceof BigDecimal) {
        return Json.value(((BigDecimal) object).doubleValue());
      }
  
      if (object instanceof Enum) {
        return Json.value(((Enum) object).name());
      }
  
      if (object instanceof Date) {
        return Json.value(DateUtils.toLongFormatFromDate((Date) object));
      }
  
      // We've passed the special-case bits, so let's try to marshal this as a
      // plain old Javabean...
  
      List<FieldWithAnnotation<Facebook>> fieldsWithAnnotation =
          findFieldsWithAnnotation(object.getClass(), Facebook.class);
  
      JsonObject jsonObject = new JsonObject();
  
      // No longer throw an exception in this case. If there are multiple fields
      // with the same @Facebook value, it's luck of the draw which is picked for
      // JSON marshaling.
      // TODO: A better implementation would query each duplicate-mapped field. If
      // it has is a non-null value and the other duplicate values are null, use
      // the non-null field.
      Set<String> facebookFieldNamesWithMultipleMappings = facebookFieldNamesWithMultipleMappings(fieldsWithAnnotation);
      if (!facebookFieldNamesWithMultipleMappings.isEmpty() && MAPPER_LOGGER.isDebugEnabled()) {
        MAPPER_LOGGER.debug(
          "Unable to convert to JSON because multiple @{} annotations for the same name are present: {}",
          Facebook.class.getSimpleName(), facebookFieldNamesWithMultipleMappings);
      }
  
      for (FieldWithAnnotation<Facebook> fieldWithAnnotation : fieldsWithAnnotation) {
        String facebookFieldName = getFacebookFieldName(fieldWithAnnotation);
        fieldWithAnnotation.getField().setAccessible(true);
  
        try {
          Object fieldValue = fieldWithAnnotation.getField().get(object);
  
          if (!(ignoreNullValuedProperties && (fieldValue == null || isEmptyCollectionOrMap(fieldValue)))) {
            jsonObject.add(facebookFieldName, toJsonInternal(fieldValue, ignoreNullValuedProperties));
          }
        } catch (Exception e) {
          throw new FacebookJsonMappingException(
            "Unable to process field '" + facebookFieldName + "' for " + object.getClass(), e);
        }
      }
  
      return jsonObject;
    }