Skip to content
Open
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
55 changes: 55 additions & 0 deletions src/JSON.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,61 @@ print(io::IO, obj, indent=nothing) = json(io, obj; pretty=something(indent, 0))
print(a, indent=nothing) = print(stdout, a, indent)
@doc (@doc json) print

"""
JSON.write_json(Vector{UInt8}, x; kw...)::Vector{UInt8}
JSON.write_json(io::IO, x; kw...)
JSON.write_json(filename::AbstractString, x; kw...)

Serialize `x` to JSON format. This function provides the same functionality as [`JSON.json`](@ref)

The first method returns the JSON output as a `Vector{UInt8}`.
The second method writes JSON output to an `IO` object.
The third method writes JSON output to a file specified by `filename` which will
be created if it does not exist yet or overwritten if it does exist.

This function is provided for backward compatibility when upgrading from
older versions of JSON.jl where the `json` function signature differed.
For new code, prefer using [`JSON.json`](@ref) directly.

See [`JSON.json`](@ref) for detailed documentation of all keyword arguments and more examples.

# Examples
```julia
# Write to IO
io = IOBuffer()
JSON.write_json(io, Dict("key" => "value"))
String(take!(io)) # "{\"key\":\"value\"}"

# Write to file
JSON.write_json("output.json", [1, 2, 3])

# Get as bytes
bytes = JSON.write_json(Vector{UInt8}, Dict("hello" => "world"))
String(bytes) # "{\"hello\":\"world\"}"
```
"""
function write_json end

function write_json(::Type{Vector{UInt8}}, x; pretty::Union{Integer,Bool}=false, kw...)
opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...)
_write_options_check(opts)
y = StructUtils.lower(opts.style, x)
buf = Vector{UInt8}(undef, sizeguess(y))
pos = json!(buf, 1, y, opts, Any[y], nothing)
resize!(buf, pos - 1)
return buf
end

function write_json(io::IO, x; kw...)
json(io, x; kw...)
end

function write_json(filename::AbstractString, x; kw...)
open(filename; write=true) do io
write_json(io, x; kw...)
end
end

@compile_workload begin
x = JSON.parse("{\"a\": 1, \"b\": null, \"c\": true, \"d\": false, \"e\": \"\", \"f\": [1,null,true], \"g\": {\"key\": \"value\"}}")
json = JSON.json(x)
Expand Down
14 changes: 9 additions & 5 deletions src/write.jl
Original file line number Diff line number Diff line change
Expand Up @@ -404,11 +404,17 @@ float_precision_check(fs, fp) = (fs == :shortest || fp > 0) || float_precision_t
@noinline _jsonlines_pretty_throw() = throw(ArgumentError("pretty printing is not supported when writing jsonlines"))
_jsonlines_pretty_check(jsonlines, pretty) = jsonlines && pretty !== false && !iszero(pretty) && _jsonlines_pretty_throw()

function json(io::IO, x::T; pretty::Union{Integer,Bool}=false, kw...) where {T}
opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...)
# throw an error if opts is not a valid WriteOptions
function _write_options_check(opts::WriteOptions)
_jsonlines_pretty_check(opts.jsonlines, opts.pretty)
float_style_check(opts.float_style)
float_precision_check(opts.float_style, opts.float_precision)
nothing
end

function json(io::IO, x::T; pretty::Union{Integer,Bool}=false, kw...) where {T}
opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...)
_write_options_check(opts)
y = StructUtils.lower(opts.style, x)
# Use smaller initial buffer size, limited by bufsize
initial_size = min(sizeguess(y), opts.bufsize)
Expand All @@ -429,9 +435,7 @@ end

function json(x; pretty::Union{Integer,Bool}=false, kw...)
opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...)
_jsonlines_pretty_check(opts.jsonlines, opts.pretty)
float_style_check(opts.float_style)
float_precision_check(opts.float_style, opts.float_precision)
_write_options_check(opts)
y = StructUtils.lower(opts.style, x)
buf = stringvec(sizeguess(y))
pos = json!(buf, 1, y, opts, Any[y], nothing)
Expand Down
15 changes: 15 additions & 0 deletions test/json.jl
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,21 @@ end
# inline_limit tests
@test JSON.json([1, 2]; pretty=2, inline_limit=3) == "[1,2]"
@test JSON.json([1, 2, 3]; pretty=2, inline_limit=3) == "[\n 1,\n 2,\n 3\n]"
# write_json
for (obj, kw, output) in [
([1, 2, 3], (;), b"[1,2,3]"),
([1, 2, 3], (;pretty=true), b"[\n 1,\n 2,\n 3\n]"),
(NaN, (;allownan=true), b"NaN"),
(NaN, (;allownan=true, nan="different nan string"), b"different nan string"),
]
@test JSON.write_json(Vector{UInt8}, obj; kw...) == output
io = IOBuffer()
@test JSON.write_json(io, obj; kw...) === nothing
@test take!(io) == output
fname = tempname()
@test JSON.write_json(fname, obj; kw...) === nothing
@test read(fname) == output
end
end
# non-Integer/AbstractFloat but <: Real output
@test_throws MethodError JSON.json(CustomNumber(3.14))
Expand Down
Loading