Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions R/pkg/R/functions.R
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,9 @@ NULL
#' }
#' @param ... additional argument(s). In \code{to_json} and \code{from_json}, this contains
#' additional named properties to control how it is converted, accepts the same
#' options as the JSON data source. In \code{arrays_zip}, this contains additional
#' Columns of arrays to be merged.
#' options as the JSON data source. Additionally \code{to_json} supports the "pretty"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would say \code{pretty}

#' option which enables pretty JSON generation. In \code{arrays_zip}, this contains
#' additional Columns of arrays to be merged.
#' @name column_collection_functions
#' @rdname column_collection_functions
#' @family collection functions
Expand Down
4 changes: 3 additions & 1 deletion python/pyspark/sql/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2295,7 +2295,9 @@ def to_json(col, options={}):
into a JSON string. Throws an exception, in the case of an unsupported type.

:param col: name of column containing a struct, an array or a map.
:param options: options to control converting. accepts the same options as the JSON datasource
:param options: options to control converting. accepts the same options as the JSON datasource.
Additionally the function supports the `pretty` option which enables
pretty JSON generation.

>>> from pyspark.sql import Row
>>> from pyspark.sql.types import *
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ private[sql] class JSONOptions(
}
val lineSeparatorInWrite: String = lineSeparator.getOrElse("\n")

/**
* Generating JSON strings in pretty representation if the parameter is enabled.
*/
val pretty: Boolean = parameters.get("pretty").map(_.toBoolean).getOrElse(false)

/** Sets config options on a Jackson [[JsonFactory]]. */
def setJacksonOptions(factory: JsonFactory): Unit = {
factory.configure(JsonParser.Feature.ALLOW_COMMENTS, allowComments)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ private[sql] class JacksonGenerator(
s"Initial type ${dataType.catalogString} must be a ${MapType.simpleString}")
}

private val gen = new JsonFactory().createGenerator(writer).setRootValueSeparator(null)
private val gen = {
val generator = new JsonFactory().createGenerator(writer).setRootValueSeparator(null)
if (options.pretty) generator.useDefaultPrettyPrinter() else generator
}

private val lineSeparator: String = options.lineSeparatorInWrite

Expand Down
4 changes: 4 additions & 0 deletions sql/core/src/main/scala/org/apache/spark/sql/functions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3619,6 +3619,8 @@ object functions {
* @param e a column containing a struct, an array or a map.
* @param options options to control how the struct column is converted into a json string.
* accepts the same options and the json data source.
* Additionally the function supports the `pretty` option which enables
* pretty JSON generation.
*
* @group collection_funcs
* @since 2.1.0
Expand All @@ -3635,6 +3637,8 @@ object functions {
* @param e a column containing a struct, an array or a map.
* @param options options to control how the struct column is converted into a json string.
* accepts the same options and the json data source.
* Additionally the function supports the `pretty` option which enables
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarification, we don't support this in JSON datasource officially since it's not documented.

* pretty JSON generation.
*
* @group collection_funcs
* @since 2.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,4 +518,25 @@ class JsonFunctionsSuite extends QueryTest with SharedSQLContext {
jsonDF.select(to_json(from_json($"a", schema))),
Seq(Row(json)))
}

test("pretty print - roundtrip from_json -> to_json") {
val json = """[{"book":{"publisher":[{"country":"NL","year":[1981,1986,1999]}]}}]"""
val jsonDF = Seq(json).toDF("root")
val expected =
"""[ {
| "book" : {
| "publisher" : [ {
| "country" : "NL",
| "year" : [ 1981, 1986, 1999 ]
| } ]
| }
|} ]""".stripMargin

checkAnswer(
jsonDF.select(
to_json(
from_json($"root", schema_of_json(lit(json))),
Map("pretty" -> "true"))),
Seq(Row(expected)))
}
}