diff --git a/DESCRIPTION b/DESCRIPTION index 7dfce7a..a512444 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: jsonlite -Version: 1.8.8 +Version: 1.8.9 Title: A Simple and Robust JSON Parser and Generator for R License: MIT + file LICENSE Depends: methods diff --git a/R/asJSON.ANY.R b/R/asJSON.ANY.R index 05013ed..3e9d170 100644 --- a/R/asJSON.ANY.R +++ b/R/asJSON.ANY.R @@ -6,19 +6,34 @@ setMethod("asJSON", "ANY", function(x, force = FALSE, ...) { } else { stop("No method for S4 class:", class(x)) } - } else if (length(class(x)) > 1) { - # If an object has multiple classes, we recursively try the next class. This is - # S3 style dispatching that doesn't work by default for formal method definitions - # There should be a more native way to accomplish this - return(asJSON(structure(x, class = class(x)[-1]), force = force, ...)) - } else if (isTRUE(force) && existsMethod("asJSON", class(unclass(x))[1])) { - # As a last resort we can force encoding using the unclassed object - return(asJSON(unclass(x), force = force, ...)) - } else if (isTRUE(force)) { + } + + ## walk the s3 class chain (if any): + if (length(class(x)) > 1) { + for (cls in class(x)[-1]) { + f <- getMethod("asJSON", cls, optional = TRUE) + if (!is.null(f)) return(f(x, ...)) + } + } + + ## fallback class: + if (isTRUE(force)) { + f <- + tryCatch({ + getMethod("asJSON", class(unclass(x))[1], optional = TRUE) ## unclass() can err, hence tryCatch() + }, error = function(e) NULL) + if (!is.null(f)) return(f(x, ...)) + } + + msg <- sprintf("No method asJSON S3 class: %s", paste0(class(x), collapse = ",")) + + ## final fallback -- encode NULL and warn: + if (isTRUE(force)) { + warning(msg) return(asJSON(NULL)) - warning("No method asJSON S3 class: ", class(x)) - } else { - # If even that doesn't work, we give up. - stop("No method asJSON S3 class: ", class(x)) } + + ## give up. + stop(msg) }) +