JSON::Create(3)
okay bestie, welcome to JSON::Create(3) β the manual page that's about to be your whole personality π
πΈ NAME πΈ
JSON::Create β literally just Create JSON. That's the vibe. β¨
π SYNOPSIS π
use JSON::Create 'create_json';
my %hash = (a => 'b', c => 'd');
print create_json (\%hash);
produces output
{"c":"d","a":"b"}
(This example is included as examples/synopsis.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/synopsis.pl> in the distribution.)
π¦ VERSION π¦
This doc describes JSON::Create version 0.36, which corresponds to git commit c6e87e42a72ce49bbb1fa92712fcbae22df2b592 <https://github.com/benkasminbullock/json-create/commit/c6e87e42a72ce49bbb1fa92712fcbae22df2b592> at Tue Apr 7 05:50:22 2026 +0900. β¨
π¦ DESCRIPTION π¦
JSON::Create encodes Perl variables into JSON. The basic routine create_json gives common defaults. The stricter version create_json_strict accepts only unambiguous inputs. For more customization, an object created with new and run with create allows specifying behaviour in more detail.
JSON::Create handles no string encoding except UTF-8. It supports serialization of objects via user-defined callbacks. Its companion module JSON::Parse parses JSON into Perl.
Errors in processing result in a warning and an undefined return value. This behaviour can be altered with the method fatal_errors.
β¨ FUNCTIONS β¨
create_json
my $json = create_json (\%hash, %args);
This converts a hash reference, array reference, or scalar into JSON. The return value is the output JSON as a string. The arguments available in %args are the same as new and set.
Details of the conversion of each type are given in "CONVERSIONS".
create_json_strict
my $json = create_json_strict (\%hash, %args);
This is the same as create_json, except that it rejects ambiguous inputs. See strict for details. It is effectively identical to
my $json = create_json (\%hash, %args, strict => 1);
The strict option can be set in %args without producing an error, but it will be overridden.
This function was added in version 0.20 of the module.
write_json
write_json ('file.json', \%hash, %options);
Write the contents of %hash (or an array reference or scalar) to the file specified in the first argument. This takes all the same arguments as create_json, new and set.
This function was added in version 0.30 of the module.
π METHODS π
If you need to alter the format of the output from the defaults of create_json or create_json_strict, create an object with new and then set preferences on that object before producing output with create.
create
my $json = $jc->create ($input);
This does exactly the same thing as create_json, unless the output format associated with $jc has been altered using "Methods for formatting the output". The return value is the output JSON.
fatal_errors
$jc->fatal_errors (1);
If this is called with a true value, errors in the input are upgraded from warnings to fatal errors.
use JSON::Create;
my $jc = JSON::Create->new ();
$jc->fatal_errors (1);
my $invalid_utf8 = "\x{99}\x{ff}\x{88}";
eval {
$jc->run ($invalid_utf8);
};
if ($@) {
print "Fatal error: $@\n";
}
produces output
Fatal error: Invalid UTF-8 at /usr/home/ben/projects/json-create/examples/fatal-errors.pl line 9.
(This example is included as examples/fatal-errors.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/fatal-errors.pl> in the distribution.)
This method was added in version 0.10 of the module.
new
my $jc = JSON::Create->new ();
Create a new JSON::Create object. Use create to generate JSON with it. It is possible to supply arguments with new:
my $jc = JSON::Create->new (%args);
All of the same values as set may be used.
set
$json->set (strict => 1, fatal_errors => 1, validate => 1);
downgrade_utf8 optionβ This corresponds todowngrade_utf8.escape_slash optionβ This corresponds toescape_slash.fatal_errors optionβ This corresponds tofatal_errors.indent optionβ This corresponds toindent.no_javascript_safe optionβ This corresponds tono_javascript_safe.non_finite_handler optionβ This corresponds tonon_finite_handler.object_handler optionβ This corresponds toobject_handler.replace_bad_utf8 optionβ This corresponds toreplace_bad_utf8.sort optionβ This corresponds tosort.strict optionβ This corresponds tostrict.type_handler optionβ This corresponds totype_handler.unicode_escape_all optionβ This corresponds tounicode_escape_all.unicode_upper optionβ This corresponds tounicode_upper.validate optionβ This corresponds tovalidate.
strict
$jc->strict (1);
This switches on rejection of ambiguous inputs, which means
- all non-data types, including objects,
- strings containing non-ASCII bytes (bytes with values of from 128 to 255) which are not marked as "utf8" (character strings),
- non-finite floating point numbers (NaN or infinite values), and
- scalar references.
Calling create with such inputs results in a return value of undef (the undefined value) and a warning being printed. You can override the behaviour for objects with obj, obj_handler, for non-data types and scalar references with type_handler, and for non-finite numbers with non_finite_handler.
The rejection of non-ASCII bytes in non-"utf8" strings cannot be overridden, so users need to ensure that all input is either ASCII-only or character string-only ("utf8").
This method was added in version 0.20 of the module.
Methods for formatting the output
These methods work on the object created with new to format the output JSON in a different way from the default when operating create.
These methods do not affect the behaviour of create_json or create_json_strict.
bool
$jc->bool ('boolean');
$jc->bool (qw/boolean JSON::Tiny::_Bool/);
Given a list of names of object types, the JSON::Create object, $jc in the example, will convert objects of these types into the JSON literals "true" or "false" depending on whether Perl thinks they're true or false.
Converting booleans to "true" and "false"
use JSON::Create;
use boolean;
my $thing = {'Yes' => true, 'No' => false};
my $jc = JSON::Create->new ();
print $jc->run ($thing), "\n";
$jc->bool ('boolean');
print $jc->run ($thing), "\n";
produces output
{"Yes":1,"No":0}
{"Yes":true,"No":false}
(This example is included as examples/boolean.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/boolean.pl> in the distribution.)
If you prefer to take over all object handling yourself, there is also obj_handler, which overrides what is set with bool.
Interoperability
The boolean values of the following Perl modules can interoperate with JSON::Create.
boolean
$jc->bool ('boolean');
JSON::Tiny
$jc->bool ('JSON::Tiny::_Bool');
Round trip compatibility is also confirmed for JSON::Tiny version 0.54.
JSON::PP
$jc->bool ('JSON::PP::Boolean');
Round trip compatibility is also confirmed for JSON::PP version 2.27300.
Types::Serialiser
$jc->bool ('JSON::PP::Boolean');
Please note the above is not a typo, JSON::PP::Boolean is the correct object type for Types::Serialiser. To confirm this, try
print ref $Types::Serialiser::false;
Mojo::JSON
$jc->bool ('JSON::PP::Boolean', 'Mojo::JSON::_Bool');
Round trip compatibility is also confirmed for Mojo::JSON version 8.65.
The current version of Mojo::JSON (Mojolicious version 8.65) uses "JSON::PP::Boolean" for true and false values. Older versions used their own type, "Mojo::JSON::_Bool".
JSON::Create's compatibility tests for Mojo::JSON compatibility are available only in the git repository as xt/mojo-json.t, rather than in the CPAN release, because different versions of Mojolicious differ a lot in not only function names but also variable names, as seen above.
You can handle multiple modules with the same object:
$jc->bool (qw/boolean JSON::Tiny::_Bool JSON::PP::Boolean/);
The compatibility of the above modules can be confirmed by running the test script t/bool.t in the distribution. However, JSON::Create does not install these modules, so unless you have installed them yourself, the tests will just be skipped.
More modules will be added to this list as time permits.
cmp
Set a user-defined routine to be used with the sort option.
Sorting the keys of objects in a user-defined order will reduce the performance of the module. The built-in variables $a and $b are not available to your sort routine, so you need to get the arguments yourself.
Sorting object elements case-independently
use utf8;
use FindBin '$Bin';
use JSON::Create;
my $jc = JSON::Create->new (sort => 1, indent => 1);
$jc->cmp (\&uccmp);
my %emojis = (
lifeforms => {
Kingkong => 'π¦',
goat => 'π',
elephant => 'π',
Grape => 'π',
Watermelon => 'π',
melon => 'π',
# What if life exists based on another element? π
siliconbased => 'β',
},
);
print $jc->run (\%emojis);
sub uccmp
{
my ($a, $b) = @_;
return uc ($a) cmp uc ($b);
}
produces output
{
"lifeforms":{
"elephant":"π",
"goat":"π",
"Grape":"π",
"Kingkong":"π¦",
"melon":"π",
"siliconbased":"β",
"Watermelon":"π"
}
}
(This example is included as examples/cmp.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/cmp.pl> in the distribution.)
This method was added in version 0.29 of the module.
downgrade_utf8
$jc->downgrade_utf8 (1);
If this is set to a true value, the return value of create_json or create is never upgraded to character strings, or utf8. This overrides the default behaviour, which is to upgrade the output to utf8 if any part of the input is utf8, or if the user has requested replacement with replace_bad_utf8 and there are bad characters in the user's input. See "UNICODE HANDLING" for details. All output of JSON::Create is valid UTF-8, regardless of what this flag is set to. See "Output is valid UTF-8".
This method was added in version 0.18 of the module. π«
escape_slash
$jc->escape_slash (1);
Call this with a true value to make the slash (known as the "solidus" in the JSON spec, bestie, they're fancy like that) get escaped with a backslash, so "/" gets turned into "\/". Call it with any false value to make the slash not be escaped β that's the default behaviour. π
Escaping slashes
use JSON::Create;
my $jc = JSON::Create->new ();
my $in = {'/dog/' => '/run/'};
print $jc->run ($in), "\n";
$jc->escape_slash (1);
print $jc->run ($in), "\n";
$jc->escape_slash (0);
print $jc->run ($in), "\n";
produces output β¨
{"/dog/":"/run/"}
{"\/dog\/":"\/run\/"}
{"/dog/":"/run/"}
(This example is included as examples/escape-slash.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/escape-slash.pl> in the distribution.)
See also "Other escapes".
This method was added in version 0.07 of the module. π¦
indent
$jc->indent (1);
Add whitespace indentation to the output. The formula it applies: add a newline plus indentation after every opening bracket, add the same after every comma, and add the same before every closing bracket. Tabs do all the indenting. How many tabs? However many brackets are currently open, bestie. Simple math, iconic results. π
Example of indentation
use JSON::Create;
my %thing = ("it's your thing" => [qw! do what you !, {wanna => 'do'}],
"I can't tell you" => [{who => 2}, qw! sock it!, 2]);
my $jc = JSON::Create->new ();
$jc->indent (1);
print $jc->run (\%thing);
produces output πΈ
{
"it's your thing":[
"do",
"what",
"you",
{
"wanna":"do"
}
],
"I can't tell you":[
{
"who":2
},
"sock",
"it",
2
]
}
(This example is included as examples/indent.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/indent.pl> in the distribution.)
Reformatting the indentation
If you prefer a different indentation style, you can totally reshape this output to your needs with simple substitutions. For example, s/^(\t+)/ " " x length ($1) /gesm; converts from tabs to two-space indentation. Slay. π«Ά
use JSON::Create;
my %thing = ("it's your thing" => [qw! do what you !, {wanna => 'do'}],
"I can't tell you" => [{who => 2}, qw! sock it!, 2]);
my $jc = JSON::Create->new ();
$jc->indent (1);
my $out = $jc->run (\%thing);
$out =~ s/^(\t+)/ " " x length ($1) /gesm;
print $out;
produces output β¨
{
"I can't tell you":[
{
"who":2
},
"sock",
"it",
2
],
"it's your thing":[
"do",
"what",
"you",
{
"wanna":"do"
}
]
}
(This example is included as examples/indent-format.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/indent-format.pl> in the distribution.)
This method was added in version 0.27 of the module. π
no_javascript_safe
$jc->no_javascript_safe (1);
Call it with a true value and it switches off JavaScript protection in the output JSON. Call it with a false value and the JavaScript protection comes right back on. Toggle city. π₯
Switching JavaScript-safety on and off
use JSON::Create;
my $in = ["\x{2028}"];
my $jc = JSON::Create->new ();
print $jc->run ($in), "\n";
$jc->no_javascript_safe (1);
print $jc->run ($in), "\n";
produces output π
["\u2028"]
[""]
(This example is included as examples/js-safe.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/js-safe.pl> in the distribution.)
See also "U+2028 and U+2029 (JavaScript clashes)".
non_finite_handler
$jc->non_finite_handler (\& handler);
This overrides the default behaviour for handling non-finite floating point numbers β in other words NaN (not a number) and negative or positive infinity β with a user-defined routine of your very own. The default behaviour of this module is described at "Floating point numbers".
Your routine handler gets the non-finite number as its sole argument, and it returns one argument: the output JSON. That's the whole deal. π
Using null for infinity and NaN
To always use null in place of the default, supply a function like this:
use JSON::Create;
my $bread = { 'curry' => -sin(9**9**9) };
my $jcnfh = JSON::Create->new ();
print $jcnfh->run ($bread), "\n";
$jcnfh->non_finite_handler(sub { return 'null'; });
print $jcnfh->run ($bread), "\n";
produces output π
{"curry":"nan"}
{"curry":null}
(This example is included as examples/non-finite-handler.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/non-finite-handler.pl> in the distribution.)
Calling convention
The non_finite_handler routine is passed a single argument and is expected to return a single argument, the JSON to output. It is called in scalar context. In other words, the call looks like this:
$json = &{$jc->{non_finite_handler}} ($item);
To pass or return multiple values via the non_finite_handler callback, use a closure. See the discussion at "obj" for an example. π§
Returning undef halts processing
If your handler returns the undefined value, create prints a warning Undefined value from user routine, halts further processing of the input, and returns the undefined value. Not the vibe, bestie, but forewarned is forearmed. π
Delete the handler with any false value
To remove the handler, just call the function without an argument:
$jc->non_finite_handler ();
or with a false argument:
$jc->non_finite_handler (0);
The behaviour then reverts to the default. Back to factory settings, periodt. π
Checking the output JSON
The JSON output by your handler may be checked for validity by switching on validation using "validate". If you don't do this, and your return value happens to contain invalid UTF-8, you may see the error Invalid UTF-8 from user routine. Please see "UTF-8 validation of user-supplied JSON" for more about this error.
Exception handling
Exceptions (die) thrown within non_finite_handler callbacks are not caught by create β they pass straight through to the parent. Please see the discussion at "obj" for an example.
This method was added in version 0.17 of the module. β
obj
$jc->obj ('Zilog::Z80' => sub { my ($obj) = @_; print "\"Z80\""; });
Register JSON generators for Perl objects! When JSON::Create finds an object with a registered type, it will call the method you've supplied. Main character energy for your objects. π
The argument to obj is a hash. The keys are object names, and the corresponding values are code references to the JSON serializer for that object:
$jc->obj (
'My::Object' => \& object_to_json,
);
The output is passed through to the output string unaltered. If you want your JSON output checked for validity, use the "validate" option.
The function is called with the object reference as its only argument, as if called like this:
my $user_json = $my_object->object_to_json ();
The return value of the function, object_to_json in the above example, must be a single value β a string containing the object's JSON encoding.
use JSON::Create;
my $jc = JSON::Create->new ();
package Zilog::Z80;
sub new { return bless { memory => '64 kbytes' }; }
sub to_json {
my ($self) = @_;
return '"I can address as many as '.$self->{memory}.' of memory"';
}
1;
package main;
my $zilog = Zilog::Z80->new ();
my %stuff = (zilog => $zilog);
print $jc->run (\%stuff), "\n";
# Set up our object's method for printing JSON.
$jc->obj (
'Zilog::Z80' => \& Zilog::Z80::to_json,
);
print $jc->run (\%stuff), "\n";
produces output π₯
{"zilog":{"memory":"64 kbytes"}}
{"zilog":"I can address as many as 64 kbytes of memory"}
(This example is included as examples/zilog.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/zilog.pl> in the distribution.)
The function is called "in scalar context", so:
use JSON::Create;
my $jc = JSON::Create->new ();
$jc->validate (1);
$jc->type_handler (sub {
return ('"a"', '"b"', '"c"');
});
print $jc->run ({ x => *STDOUT });
produces output β¨
{"x":"c"}
(This example is included as examples/too-many-values.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/too-many-values.pl> in the distribution.)
If you need to pass or return more than a single argument, use a closure:
use JSON::Create;
package My::Cool::Object;
sub new { return bless {}; }
sub serialize { return ('true', 'false'); };
1;
package main;
my $object = My::Cool::Object->new ();
my $jc = JSON::Create->new ();
my ($arg1, $arg2);
$jc->obj (
'My::Cool::Object' => sub {
my ($obj) = @_;
my ($value1, $value2) = My::Cool::Object::serialize ($obj, $arg1, $arg2);
return $value2;
},
);
print $jc->run ({cool => $object});
produces output π¦
{"cool":false}
(This example is included as examples/closure.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/closure.pl> in the distribution.)
Throwing an exception in your callback
Exceptions (fatal errors) are not caught by JSON::Create, so if you want to halt the execution of JSON::Create, you can throw an exception right inside your callback. Your callback, your rules, bestie. π
use JSON::Create;
package Funky::Monkey::Baby; sub new {return bless {};} 1;
package main;
my $jc = JSON::Create->new ();
$jc->obj (
'Funky::Monkey::Baby' => sub {
die "There is no such thing as a funky monkey baby";
},
);
eval {
$jc->run ({fmb => Funky::Monkey::Baby->new ()});
};
if ($@) {
print "$@\n";
}
and it spits out π
There is no such thing as a funky monkey baby at /usr/home/ben/projects/json-create/examples/exception.pl line 10.
(yes bestie, this whole thing ships as examples/exception.pl β you can find it at https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/exception.pl in the distro.)
If you're the type who wants to handle every single object yourself, no delegating, no sharing β there's obj_handler for that. π
And real talk: if your handler returns the undefined value, create will print a warning that says Undefined value from user routine, halt all further processing of the input, and hand you back the undefined value. Not a vibe, but forewarned is forearmed. β¨
π obj_handler π
$jc->obj_handler (\& my_obj_handler);
You hand it an object handler, and boom β every object goes through your routine. Want to replace all objects with 'null'? Do it. Want to die the second an object shows up? Also do it. Your world, your rules. π
- Calling convention β your
obj_handlerroutine gets exactly one argument and is expected to give exactly one back: the JSON to output. It gets called in scalar context, so like literally the call looks like this:
$json = &{$jc->{obj_handler}} ($item);
Wanna pass or return multiple values through the obj_handler callback? Use a closure, bestie. There's a whole example waiting for you over in obj.
- Returning undef halts processing β if your handler returns the undefined value,
createprints the warningUndefined value from user routine, halts further processing of the input, and returns the undefined value. So like, don't do that unless you mean it. π - Delete the handler with any false value β wanna yeet the handler? Just call the function with no argument:
$jc->obj_handler ();
or with a false one:
$jc->obj_handler (0);
and everything goes back to the default behaviour. So chill. π§
- Checking the output JSON β the JSON your handler spits out can be validity-checked if you flip on validation with
validate. If you don't do that and your return value happens to have invalid UTF-8 in it, you might run into the errorInvalid UTF-8 from user routine. Full lore on that one lives atUTF-8 validation of user-supplied JSON. - Exception handling β exceptions (
die) thrown insideobj_handlercallbacks are not caught bycreate. They get passed straight up to the parent. There's an example over atobjif you want the receipts.
π Turning various types of object into JSON π
Okay so here's the whole vibe β handling a bunch of different object types with a user-supplied handler:
use utf8;
use FindBin '$Bin';
use JSON::Create;
package Monkey::Shines;
sub new { return bless {}; }
1;
package Monkey::Shines::Bool;
sub true { my $monkey = 1; return bless \$monkey; }
sub false { my $monkey = 0; return bless \$monkey; }
1;
package main;
my $monkeys = {
CuriousGeorge => Monkey::Shines->new (),
KingKong => Monkey::Shines::Bool->true (),
FunkyKong => Monkey::Shines::Bool->false (),
PeterTork => "Monkees",
};
my $obj_handler = sub {
my ($obj) = @_;
if (ref ($obj) =~ /bool/i) {
return $$obj ? 'true' : 'false';
}
else {
return 'null';
}
};
my $jc = JSON::Create->new (indent => 1, sort => 1);
print $jc->run ($monkeys), "\n";
$jc->obj_handler ($obj_handler);
print $jc->run ($monkeys), "\n";
$jc->obj_handler ();
print $jc->run ($monkeys), "\n";
and it produces:
{
"CuriousGeorge":{},
"FunkyKong":0,
"KingKong":1,
"PeterTork":"Monkees"
}
{
"CuriousGeorge":null,
"FunkyKong":false,
"KingKong":true,
"PeterTork":"Monkees"
}
{
"CuriousGeorge":{},
"FunkyKong":0,
"KingKong":1,
"PeterTork":"Monkees"
}
(this one lives in the distro as examples/obj-handler.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/obj-handler.pl if you wanna peek. π¦)
β¨ Turning everything into JSON β¨
And here's a "try harder" routine that kinda does what the JSON module does β it goes looking for methods on all the objects:
use utf8;
use FindBin '$Bin';
use JSON::Create 'create_json';
use Mojo::URL;
use Path::Tiny;
sub try_harder
{
my ($obj) = @_;
my $type = ref $obj;
if ($obj->can ('TO_JSON')) {
print "Jsonifying $type with 'TO_JSON'.\n";
return create_json ($obj->TO_JSON ());
}
elsif ($obj->can ('to_string')) {
print "Stringifying $type with 'to_string'.\n";
# The call to "create_json" makes sure that the string is
# valid as a JSON string.
return create_json ($obj->to_string ());
}
else {
return create_json ($obj);
}
}
my $jc = JSON::Create->new (indent => 1, sort => 1, validate => 1);
$jc->obj_handler (\& try_harder);
print $jc->run ({
url => Mojo::URL->new('http://sri:foo@example.com:3000/foo?foo=bar#23'),
path => path ('/home/ben/software/install/bin/perl'),
}), "\n";
output:
Jsonifying Path::Tiny with 'TO_JSON'.
Stringifying Mojo::URL with 'to_string'.
{
"path":"/home/ben/software/install/bin/perl",
"url":"http://example.com:3000/foo?foo=bar#23"
}
(this one is examples/try-harder.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/try-harder.pl. π)
Heads up though: thisobj_handleroverrides whatever you set withboolorobj. Currently it does not warn you about that. SeeBUGS. And the routine you use to handle objects might be the same one you use to handle types β seetype_handler. All the callback details live underobj.
This method was added in version 0.13 of the module. π
π replace_bad_utf8 π
$jc->replace_bad_utf8 (1);
Instead of throwing the warning or error Invalid UTF-8, this swaps invalid UTF-8 in the inputs for the Unicode replacement character U+FFFD. So forgiving. So demure. β¨
Now, subtle-but-important: if you use replace_bad_utf8 on input that contains only strings not marked as character strings, and bad UTF-8 gets found, JSON::Create marks the output as a character string. Otherwise that replacement character is literally just a lil pile of broken bytes. You can change that behaviour with the downgrade_utf8 method.
Added in version 0.12 of the module. π
πΈ set_fformat πΈ
$jc->set_fformat ('%e');
This sets the printf-style format string used to print floating point numbers. It gets validated, and if the format can't be used you get a warning. The format is also capped at a maximum length to stop buffer overflows happening inside the module. Safety first, bestie. π«Ά
Setting the format of floating point numbers
use JSON::Create;
my $jc = JSON::Create->new ();
my @array = (1000000000.0,3.141592653589793238462643383279502884197169399375105820974944592307816406,0.000000001);
print $jc->run (\@array), "\n";
$jc->set_fformat ('%.3f');
print $jc->run (\@array), "\n";
$jc->set_fformat ('%E');
print $jc->run (\@array), "\n";
$jc->set_fformat ();
print $jc->run (\@array), "\n";
output:
[1e+09,3.14159,1e-09]
[1000000000.000,3.142,0.000]
[1.000000E+09,3.141593E+00,1.000000E-09]
[1e+09,3.14159,1e-09]
(this one is examples/set-fformat.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/set-fformat.pl. π)
Added in version 0.07 of the module. β
π sort π
$jc->sort (1);
Sorts your hash keys. Default is Perl's plain string sorting. Wanna bring your own ordering? Feed it a cmp and go off. And no β this does not touch the order of array elements, only hash keys. Arrays stay exactly where they are, they're not the problem. π
JSON with indentation and sorted keys
use utf8;
use JSON::Create;
my %emojis = (
animals => {
kingkong => 'π¦',
goat => 'π',
elephant => 'π',
},
fruit => {
grape => 'π',
watermelon => 'π',
melon => 'π',
},
baka => { # Japanese words
'γ°' => 'γ',
'γ' => 'γ»',
'γΎ' => 'γ¬γ',
},
);
my $jc = JSON::Create->new ();
my @moons = qw!π π π π π π π π!;
my $i = 0;
for (@moons) {
$emojis{moons}{$_} = $i;
$i++;
}
$jc->sort (1);
$jc->indent (1);
print $jc->run (\%emojis);
output:
{
"animals":{
"elephant":"π",
"goat":"π",
"kingkong":"π¦"
},
"baka":{
"γ":"γ»",
"γ°":"γ",
"γΎ":"γ¬γ"
},
"fruit":{
"grape":"π",
"melon":"π",
"watermelon":"π"
},
"moons":{
"π":0,
"π":1,
"π":2,
"π":3,
"π":4,
"π":5,
"π":6,
"π":7
}
}
(you guessed it, examples/sort.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/sort.pl. π)
Added in version 0.29 of the module. π¦
π₯ type_handler π₯
$jc->type_handler (sub {return 'null'});
okay so bestie, by default, when JSON::Create bumps into a variable of a type it just does not know what to do with β think a glob, or a code ref β it prints a warning and hands you back an undefined value. (More on that in "Code, regexes, and other references".) The method type_handler is the glow-up: it sets up a callback that fires whenever a variable of an unhandled type shows up in the input. So like, if you wanna drop the JSON literal null into the output when you hit a reference to an unhandled type, instead of screaming an error β the example up above does exactly that. π
- Calling convention β the
type_handlerroutine gets passed a single argument and is expected to return a single argument: the JSON to output. It's called in scalar context. In other words, the call looks like this:
$json = &{$jc->{type_handler}} ($item);
If you wanna pass or return multiple values through the type_handler callback, use a closure. There's an example over in the discussion at "obj".
- Returning undef halts processing β if your handler returns the undefined value,
createprints a warning"Undefined value from user routine", halts any further processing of the input, and returns the undefined value. like, full stop, bestie π - Delete the handler with any false value β to remove the handler, just call the function with no argument,
$jc->type_handler ();
or with a false argument:
$jc->type_handler (0);
The behaviour then reverts to the default. so chill
- Checking the output JSON β the JSON your handler spits out can be checked for validity by switching on validation with "validate". If you don't use it, and your return value happens to contain invalid UTF-8, you might see the error
"Invalid UTF-8 from user routine". Peep "UTF-8 validation of user-supplied JSON" for more about this error. π - Exception handling β exceptions (
die) thrown insidetype_handlercallbacks are not caught bycreate; they get passed straight through to the parent. See the discussion at "obj" for an example.
Ways to handle types
The following example shows a few possibilities for handling types:
use utf8;
use FindBin '$Bin';
use JSON::Create 'create_json';
my %crazyhash = (
'code' => sub { return "κ°λ¨μ€νμΌ"; },
'regex' => qr/.*/,
'glob' => *STDOUT,
);
# Let's validate the output of the subroutine below.
my $jc = JSON::Create->new (validate => 1, indent => 1, sort => 1);
# Try this one weird old trick to convert your Perl type.
$jc->type_handler (
sub {
my ($thing) = @_;
my $value;
my $type = ref ($thing);
if ($type eq 'CODE') {
$value = &$thing;
}
else {
$value = "$thing";
}
return create_json ({ type => $type, value => $value, },
indent => 1, sort => 1);
}
);
print $jc->run (\%crazyhash), "\n";
produces output
{
"code":{
"type":"CODE",
"value":"κ°λ¨μ€νμΌ"
},
"glob":{
"type":"GLOB",
"value":"GLOB(0x209a82a0)"
},
"regex":{
"type":"Regexp",
"value":"(?^:.*)"
}
}
(This example is included as examples/type-handler.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/type-handler.pl> in the distribution.) π
If the strict option is chosen, this method is also passed scalar references. plot twist
use JSON::Create;
my $jc = JSON::Create->new ();
$jc->strict (1);
print "Before: ", $jc->run (\1), "\n";
$jc->type_handler (sub {
my ($thing) = @_;
if (ref $thing eq 'SCALAR') {
return $$thing;
}
});
print "After: ", $jc->run (\1), "\n";
produces output
Input's type cannot be serialized to JSON at /usr/home/ben/projects/json-create/examples/type-handler-scalar.pl line 7.
Use of uninitialized value in print at /usr/home/ben/projects/json-create/examples/type-handler-scalar.pl line 7.
Before:
After: 1
(This example is included as examples/type-handler-scalar.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/type-handler-scalar.pl> in the distribution.)
This method was added in version 0.10 of the module. β
unicode_escape_all
$jc->unicode_escape_all (1);
Call this with a true value to make all Unicode characters be escaped into the "\u3000" format. A false value switches that off again. π¦
Escape all Unicode
use JSON::Create;
use utf8;
my $jc = JSON::Create->new ();
my $in = 'θ΅€γΓΆοΌ‘βΟͺ';
print $jc->run ($in), "\n";
$jc->unicode_escape_all (1);
print $jc->run ($in), "\n";
$jc->unicode_upper (1);
print $jc->run ($in), "\n";
$jc->unicode_escape_all (0);
print $jc->run ($in), "\n";
produces output
"θ΅€γΓΆοΌ‘βΟͺ"
"\u8d64\u30d6\u00f6\uff21\u2182\u03ea"
"\u8D64\u30D6\u00F6\uFF21\u2182\u03EA"
"θ΅€γΓΆοΌ‘βΟͺ"
(This example is included as examples/escape-all.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/escape-all.pl> in the distribution.)
Output is always UTF-8
Note that JSON::Create contains its own UTF-8 validation, and this escaping is applied regardless of whether Perl marks the bytes as "utf8" or not: π
use JSON::Create;
no utf8;
my $jc = JSON::Create->new ();
my $in = 'θ΅€γΓΆοΌ‘βΟͺ';
print $jc->run ($in), "\n";
$jc->unicode_escape_all (1);
print $jc->run ($in), "\n";
$jc->unicode_upper (1);
print $jc->run ($in), "\n";
$jc->unicode_escape_all (0);
print $jc->run ($in), "\n";
produces output
"θ΅€γΓΆοΌ‘βΟͺ"
"\u8d64\u30d6\u00f6\uff21\u2182\u03ea"
"\u8D64\u30D6\u00F6\uFF21\u2182\u03EA"
"θ΅€γΓΆοΌ‘βΟͺ"
(This example is included as examples/escape-all-no-utf8.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/escape-all-no-utf8.pl> in the distribution.)
See also "Input strings must be UTF-8". πΈ
unicode_upper
$jc->unicode_upper (1);
Call this with a true value to make Unicode escapes use upper case letters in the hexadecimal. There's an example under "unicode_escape_all". π
validate
$jc->validate (1);
If this is called with a true value, JSON::Create validates the user-generated JSON given by the callbacks registered with "obj", "type_handler", "obj_handler" and "non_finite_handler". The validation is done via the routine assert_valid_json of JSON::Parse, so that module must be installed β otherwise the call to validate will fail. This also validates that the return value contains only valid UTF-8. β
If JSON::Parse is installed, and the JSON fails to validate, a warning will be produced containing the invalid JSON string and the error produced by assert_valid_json, and the return value will be undefined.
This method was added in version 0.07 of the module.
β¨ CONVERSIONS β¨
This section details what conversions are applied to the various inputs to produce outputs. the receipts, basically π§Ύ
Hashes
JSON::Create turns associative arrays into JSON objects. The keys are written into JSON as strings, with control characters escaped. The order of the keys is as they are supplied by Perl. π
use JSON::Create 'create_json';
my %example = (
x => 1,
y => 2,
z => 3,
);
print create_json (\%example);
produces output
{"y":2,"x":1,"z":3}
(This example is included as examples/hash.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/hash.pl> in the distribution.)
Nested hashes are recursively followed:
use JSON::Create 'create_json';
my %example = (
x => {
y => 2,
z => 3,
},
a => {
b => 4,
c => 5,
},
);
print create_json (\%example);
produces output
{"x":{"z":3,"y":2},"a":{"b":4,"c":5}}
(This example is included as examples/nested-hash.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/nested-hash.pl> in the distribution.)
Arrays
Arrays are converted to JSON arrays. The order of elements of the array is left unchanged. no shuffling, we respect the lineup π
use JSON::Create 'create_json';
my @array = (1, 2, 2.5, qw/mocha dusty milky/, qw/Tico Rocky Pinky/);
print create_json (\@array);
produces output
[1,2,2.5,"mocha","dusty","milky","Tico","Rocky","Pinky"]
(This example is included as examples/array.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/array.pl> in the distribution.)
Nested arrays are recursively followed:
use JSON::Create 'create_json';
my @array = ([1, 2, 2.5], [qw/mocha dusty milky/], [qw/Tico Rocky Pinky/]);
print create_json (\@array);
produces output
[[1,2,2.5],["mocha","dusty","milky"],["Tico","Rocky","Pinky"]]
(This example is included as examples/nested-array.pl <https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/nested-array.pl> in the distribution.)
Nested hashes and arrays are converted similarly:
use JSON::Create 'create_json';
my $nested = {
numbers => [1, 2, 2.5, 99.99],
cats => [qw/mocha dusty milky/],
dogs => [qw/Tico Rocky Pinky/],
fruit => {
thai => 'pineapple',
japan => 'persimmon',
australia => 'orange',
},
};
print create_json ($nested, sort => 1, indent => 1);
produces output
{
"cats":[
"mocha",
"dusty",
"milky"
],
"dogs":[
"Tico",
"Rocky",
"Pinky"
],
"fruit":{
"australia":"orange",
"japan":"persimmon",
"thai":"pineapple"
},
"numbers":[
1,
2,
2.5,
99.99
]
}
iconic. no notes. π¦
(This example is included as examples/nested.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/nested.pl β in the distribution.)
π Scalars
Non-reference Perl scalars get turned into JSON strings or numbers, depending on what Perl thinks they're holding. That's it, that's the vibe check. β¨
π Strings
As far as possible, strings are written as they are to the JSON. No cap.
JSON is Unicode, so all output gets checked for Unicode validity. Further, this module insists on UTF-8. (See "Input strings must be UTF-8".) Invalid UTF-8 within input strings produces the error Invalid UTF-8 and the undefined value is returned. You can change that behaviour with the method replace_bad_utf8. (For full details of the corner cases, see "UNICODE HANDLING".) π¦
Some whitespace and control characters must be also escaped for the output to be valid JSON. (See "RFC 8259".) It's giving "required by the spec", bestie. π
In addition to this, create_json_strict or the strict option reject inputs containing non-ASCII bytes (bytes with values of from 128 to 255) which are not marked as character strings. Periodt. π
π Control characters and whitespace
To form valid JSON, bytes of value less than 0x20 in a Perl string must be converted into JSON escapes, either the whitespace escapes \b (backspace) \r, \t, \n, and \f, or the form \u0001 for other control characters. Further, the backslash must be written as "\\" and double quotes must be written as "\"". Not me having to escape everything β but that's literally the rules. π
This example demonstrates some of the necessary escaping:
use JSON::Create 'create_json';
# An example string containing various things.
my $weirdstring = {weird => "\t\r\n\x00 " . '"' . '\\' . '/' };
print create_json ($weirdstring);
produces output
{"weird":"\t\r\n\u0000 \"\\/"}
(This example is included as examples/weirdstring.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/weirdstring.pl β in the distribution.)
πΈ U+2028 and U+2029 (JavaScript clashes)
my $out = create_json (["\x{2028}"]);
# $out = '["\u2028"]'
Although it is not required by the JSON standard, JSON::Create by default escapes Unicode code points U+2028 and U+2029 as "\u2028" and "\u2029" for JavaScript compatibility. This behaviour can be altered with the method no_javascript_safe. π«Ά
This escaping is necessary for JavaScript because of a clash between the JSON standard and the JavaScript (ECMAScript) standard. The characters U+2028 ("LINE SEPARATOR" in the Unicode standard) and U+2029 ("PARAGRAPH SEPARATOR" in the Unicode standard) are valid within JSON, as defined by "RFC 8259", but invalid within JavaScript strings, as defined by the ECMA standard (See ECMA Standard ECMA-262, "ECMAScript Language Specification", 3rd Edition, section 7.3 "Line Terminators"). Two standards beefing, and you're caught in the middle. π
β Other escapes
The forward slash, /, known as "solidus" in the JSON specification, does not have to be escaped, and JSON::Create's default is not to escape it. This behaviour can be altered with the method escape_slash.
Other Unicode values are not escaped. This behaviour can be altered with the method unicode_escape_all. π
π Integers
Integers are printed in the usual way. Perl may interpret an integer with a very large absolute value to be a floating point number, and this module will print it out as such. See also "Context-dependent variables" for the handling of variables with both string and integer values.
π Floating point numbers
Finite floating point numbers are printed using printf formatting via "%g", like
printf ("%g", $number);
This behaviour can be altered with the method set_fformat.
JSON does not allow NaN or infinity as bare values. From page 6 of "RFC 8259":
Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted.
create_json converts NaN (not a number) values to "nan" (the letters "nan" surrounded by double quotes), and positive and negative infinity to "inf" and "-inf" respectively. iconic behaviour honestly π
create_json_strict disallows non-finite numbers. If a non-finite number appears within its input, it prints a warning Non-finite number in input and returns the undefined value:
use JSON::Create 'create_json_strict';
print create_json_strict (9**9**9);
produces output
Non-finite number in input at /usr/home/ben/projects/json-create/blib/lib/JSON/Create.pm line 200.
Use of uninitialized value in print at /usr/home/ben/projects/json-create/examples/strict-non-finite.pl line 5.
(This example is included as examples/strict-non-finite.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/strict-non-finite.pl β in the distribution.)
A JSON::Create object created with new converts in the same way as create_json. This behaviour can be altered with the method non_finite_handler. If strict is specified, non-finite numbers are passed to non_finite_handler if it is set, and if not, it prints a warning Non-finite number in input and returns the undefined value. π
π¦ The undefined value
Undefined values in the input are mapped to the JSON literal null.
use JSON::Create 'create_json';
print create_json ({a => undef, b => [undef, undef]}), "\n";
produces output
{"a":null,"b":[null,null]}
(This example is included as examples/undef.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/undef.pl β in the distribution.)
π Booleans
Booleans (true and false) from input via JSON::Parse version 0.37 or later will be turned into the outputs true and false:
use JSON::Parse '0.38', 'parse_json';
use JSON::Create 'create_json';
my $in = parse_json ('[true,false,"boo"]');
print create_json ($in);
produces output
[true,false,"boo"]
(This example is included as examples/json-parse-bool.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/json-parse-bool.pl β in the distribution.)
Other kinds of object can be converted to booleans using the method bool (see below). π₯
π Context-dependent variables
A context-dependent variable is a variable which may contain a string and a numerical value. Usually the string value is just a representation of the number, but it may not be. The behaviour in the case of a context-dependent variable is as follows. π
If the variable contains a valid numerical value, the numerical value is used in the output JSON, rather than the string value. However, some modules, like charinfo in Unicode::UCD, return context-dependent hash values which have a non-number-like string under the key script with values such as "Latin" or "Common" but no valid numerical value, despite being marked as context-dependent variables. In such cases, the string value is used. (In terms of XS, if the scalar is marked as "SVt_PVIV" or "SVt_PVNV", the scalar is tested with "SvIOK" or "SvNOK" respectively, and if this is true the numerical value is used, if false the string value is used.) ngl that's a whole saga
Up to version 0.25, this module wrongly assumed that the string part of a context-dependent variable would always be a valid representation of a number, and the string was added to the output without quote marks. In version 0.26, checking was done to see if the string actually was a number. In version 0.27 this approach was abandoned and the numerical value was given precedence. In version 0.28 this was again altered for the sake of unusual cases like the script key returned by charinfo in Unicode::UCD, where the scalar is marked as having a numerical value but does not in fact contain a valid numerical value. The glow-up was real. β¨
π§ Other types
JSON::Create is meant to provide serialization of data types. It does not provide built-in serialization of Perl objects and other non-data types, such as code references or regular expressions, beyond a few basic defaults. How to handle non-data types is left completely up to users. These basic defaults, and how to set up more extensive handling, are described in the following subsections. π«Ά
π Scalar references
create_json dereferences scalar references, then treats them as scalars in the way described in "Scalars".
create_json_strict rejects scalar references. Input containing a scalar reference causes a warning Input's type cannot be serialized to JSON and the undefined value to be returned.
A JSON::Create object created with new behaves as create_json unless the strict option is specified. If the strict option is specified, scalar references are passed through to type_handler if it is set, otherwise input containing a scalar reference causes a warning Input's type cannot be serialized to JSON and the undefined value to be returned. π«
π Objects
create_json handles Perl objects as if non-object types. In other words, unless you specify object handling, it breaks encapsulation. bestie that's so unserious of it π
create_json_strict rejects input containing Perl objects. If the input contains an object (a blessed reference), a warning Object cannot be serialized to JSON is printed and the undefined value returned.
A JSON::Create object created with new can handle specified types of object with method obj, or with a general object handler supplied via obj_handler. By default it behaves like create_json. If strict is chosen, it rejects input containing Perl objects unless the user sets a handler for them with obj or obj_handler. π
π Code, regexes, and other references
A code or other reference (regexes, globs, etc.) in the input of create_json or create_json_strict prints a warning Input's type cannot be serialized to JSON and causes the entire return value to be the undefined value. This behaviour can be altered with the method type_handler. not the whole return value catching strays π
β¨ EXPORTS β¨
The module exports nothing except by request. Two functions, create_json and create_json_strict, are exported on request. There is also an export tag all if you require both functions:
use JSON::Create ':all';
ask and you shall receive, that's the energy π«Ά
πΈ INSTALLATION πΈ
The module uses C internally, so you need a C compiler to install it. If the compiled library cannot be loaded, there is also a backup "pure Perl" module JSON::Create::PP in the distribution. two paths, both slay π
π UNICODE HANDLING π
okay bestie this section is lowkey the β¨loreβ¨ of how JSON::Create deals with Unicode inside strings. and the whole thing hinges on two things with deeply confusingly similar names: Perl character strings, which we call "utf8", and the actual Unicode encoding "UTF-8". yeah. one is a Perl flag, one is a byte format. they are NOT the same and the entire section is basically about that π
π¦ UTF-8 only
JSON::Create only consumes and produces the UTF-8 encoding of Unicode. that's it. that's the whole menu. if you need a different encoding, pls go use the Encode module to encode the output yourself, bestie π«Ά
π Input strings must be UTF-8
All strings within the input must be UTF-8 encoded. and listen β this does not mean the strings must be Perl character strings (Perl's "utf8"). it means the input strings must be valid UTF-8. input strings can be either Perl character strings or bytes, but either way, the bytes of the string must be valid UTF-8. no exceptions, no vibes-based exceptions, periodt β
to illustrate, look at this example:
use JSON::Create 'create_json';
use utf8;
$| = 1;
print create_json ('θ΅€γΓΆοΌ‘βΟͺ'), "\n";
no utf8;
binmode STDOUT, ":raw";
print create_json ('θ΅€γΓΆοΌ‘βΟͺ'), "\n";
print create_json ("\x99\xff\x10"), "\n";
and it produces output:
"θ΅€γΓΆοΌ‘βΟͺ"
"θ΅€γΓΆοΌ‘βΟͺ"
Invalid UTF-8 at /usr/home/ben/projects/json-create/blib/lib/JSON/Create.pm line 192.
Use of uninitialized value in print at /usr/home/ben/projects/json-create/examples/valid-chars.pl line 12.
(this example is included as examples/valid-chars.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/valid-chars.pl in the distribution.)
the point here, and this is the whole point: the UTF-8 validation is carried out regardless of whether Perl thinks the input string is "utf8". that third call to create_json? Perl did not mark that string as utf8, and it still fails as invalid UTF-8. it's giving equal-opportunity validation π
and this insistence on UTF-8 within input strings is related to the whole "Unicode upgrades are not done according to Perl conventions" thing below π
β Output is valid UTF-8
All of the output of either the function create_json or the method create is valid UTF-8. again β this does not mean the output strings are marked as Perl character strings ("utf8"). it means the output has been validated as UTF-8. validation β marking, bestie, they're different things and the distinction is literally the whole vibe of this page.
now. there is one exception to this. for user-generated JSON returned by obj, obj_handler, type_handler and non_finite_handler, the parts of the output consisting of return values from user routines may be non-UTF-8-compliant if the user has not switched on validation with validate, and there are no character strings ("utf8") anywhere in the input. HOWEVER β if there are any Perl character strings ("utf8") anywhere in the input, and the user has not chosen downgrade_utf8, then JSON::Create validates the entire output as UTF-8, as described in "UTF-8 validation of user-supplied JSON". the loophole gets closed, babes πͺπ
π Unicode upgrades are not done according to Perl conventions
here's the tea β if a single string anywhere in the input is a Perl character string β in other words, marked as "utf8" β then the entire output string is marked as a Perl character string, "utf8", without altering the non-"utf8" bytes.
and yeah, this is at odds with Perl conventions. Perl says that non-"utf8" strings actually consist of characters with symbols from 0 to 255 which "coincidentally" fit into one byte, and "utf8" strings actually consist of characters with values from 0 to 0x10FFFF, not bytes. and when you combine the two, it's illegal to treat either of them as bytes β instead they must both be treated as numbers. that's the Perl way.
to illustrate, here's JSON's behaviour contrasted with JSON::Create's:
use utf8;
use FindBin '$Bin';
use JSON;
use JSON::Create 'create_json';
no utf8;
my $x = 'γγγγγ';
use utf8;
my $y = 'γγγγγ';
my $v = {x => $x, y => $y};
print to_json ($v), "\n";
print create_json ($v), "\n";
which produces output:
{"x":"ããããã","y":"γγγγγ"}
{"x":"γγγγγ","y":"γγγγγ"}
(this example is included as examples/json-unicode.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/json-unicode.pl in the distribution.)
so the Perl convention is: if a non-utf8 string and a utf8 string get combined, they should be combined the way JSON does it β by treating each byte of the non-utf8 string as if it's a single Unicode code point, and writing equivalent UTF-8 bytes for that code point into the output. JSON::Create does a different thing: it insists that all input strings must be valid UTF-8, and after validating them, it combines them with the "utf8" strings without altering their contents.
this break with the Perl convention is by design. it's not a bug, bestie, it's a lifestyle choice π
and here's an example that illustrates what happens with non-UTF-8 bytes:
use JSON;
use JSON::Create 'create_json';
use Gzip::Faster;
$|=1;
# Generate some random garbage bytes
my $x = gzip ('γγγγγ');
use utf8;
my $y = 'γγγγγ';
my $v = {x => $x, y => $y};
print to_json ($v), "\n";
print create_json ($v), "\n";
which produces output:
{"x":"\u001f\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003{ΓΓΓ½ΒΈΒ±Γ·qcΓΏΓ£Γ\u001b'\u0003\u0000Β£ Β³\u0012\u000f\u0000\u0000\u0000","y":"γγγγγ"}
Invalid UTF-8 at /usr/home/ben/projects/json-create/blib/lib/JSON/Create.pm line 192.
Use of uninitialized value in print at /usr/home/ben/projects/json-create/examples/json-unicode-gzip-bytes.pl line 15.
(this example is included as examples/json-unicode-gzip-bytes.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/json-unicode-gzip-bytes.pl in the distribution.)
πΈ Using replace_bad_utf8 may cause a utf8 upgrade
please see the discussion under replace_bad_utf8. that's it, that's the section, go read the other section π
π§ UTF-8 validation of user-supplied JSON
okay so this one is important. if you supply JSON via a user routine such as obj_handler, and you choose not to validate your output with validate, and the input contains a character string ("utf8"), and you do not choose downgrade_utf8 β then the entire output string has to be validated as UTF-8. why? to prevent a loophole where a string containing non-UTF-8 compliant bytes could get upgraded to a character string ("utf8"). we're not letting that sneak through, no ma'am π«
in this case, if invalid UTF-8 is detected, the diagnostic Invalid UTF-8 from user routine is printed, and the undefined value is returned. and since the check is applied to the final output JSON, there's no information about which routine was at fault π so if you want a more specific diagnosis, please switch on validate.
here's an example of how this may occur:
use JSON::Create;
my $jc = JSON::Create->new ();
# This type handler returns a non-UTF-8 string.
$jc->type_handler (sub {return '"'. pack ("CCC", 0x99, 0x10, 0x0) . '"';});
use utf8;
# sub {1} triggers the type handler for a code reference, and the γΆγΌ
# contains a "utf8" flag, so this combination sets off the problem.
print $jc->run ({a => sub {1}, b => 'γΆγΌ'});
which produces output:
Invalid UTF-8 from user routine at /usr/home/ben/projects/json-create/examples/user-bad-utf8.pl line 11.
Use of uninitialized value in print at /usr/home/ben/projects/json-create/examples/user-bad-utf8.pl line 11.
(this example is included as examples/user-bad-utf8.pl β https://fastapi.metacpan.org/source/BKB/JSON-Create-0.36/examples/user-bad-utf8.pl in the distribution.)
π₯ DIAGNOSTICS π₯
all diagnostics are warnings by default. you can change that behaviour with the method fatal_errors. so if you want them to be, like, fatal, you absolutely can. main character energy, your call π
π Input's type cannot be serialized to JSON
(Warning) A reference type such as a code reference, regexp, or glob was found in the user's input. for a discussion, see "Code, regexes, and other references". for how to overcome this, see type_handler. slay your way out of it π
π Invalid UTF-8
(Warning) Bytes in a Perl string were not valid UTF-8. this behaviour can be altered with the method replace_bad_utf8.
π Invalid UTF-8 from user routine
(Warning) A return value from a user routine was not valid UTF-8. see "UTF-8 validation of user-supplied JSON".
this diagnostic and the corresponding validation of user-supplied JSON was added in version 0.19 of the module.
β¨ JSON::Parse::assert_valid_json failed
(Warning) The user requested validation with validate and this failed. yeah. it failed. that's the whole story.
π Non-ASCII byte in non-utf8 string
(Warning) The user tried to encode a string containing a non-ASCII byte in a non-"utf8" string. this diagnostic occurs with either create_json_strict or strict.
this diagnostic was added in version 0.20 of the module together withcreate_json_strictand thestrictmethod.
π Non-finite number in input
(Warning) A number which cannot be represented as a floating point number was found in the input. see "Floating point numbers".
this diagnostic was added in version 0.20 of the module together withcreate_json_strictand thestrictmethod.
π Object cannot be serialized to JSON
(Warning) An object in the input could not be serialized to JSON. see "Objects" for a discussion.
this diagnostic was added in version 0.20 of the module together withcreate_json_strictand thestrictmethod.
π«Ά Undefined value from user routine
(Warning) An undefined value was returned by a user routine set with either obj, obj_handler, type_handler or non_finite_handler.
π₯ PERFORMANCE π₯
okay so bestie, you wanna know if this thing is fast? there's literally a benchmarking script sitting in bench/bench.pl and it does a whole side-by-side with JSON::XS and Cpanel::JSON::XS. the outputs look like this, and the improve column is showing you how much faster the fastest module was compared to the slowest one:
Versions used:
+-----+------------------+---------+
| CJX | Cpanel::JSON::XS | 4.25 |
+-----+------------------+---------+
| JX | JSON::XS | 4.03 |
+-----+------------------+---------+
| JC | JSON::Create | 0.29_02 |
+-----+------------------+---------+
Comparing hash of ASCII strings...
Repetitions: 1000 x 200 = 200000
+--------+--------+------------+---------+
| Module | 1/min | min | improve |
+--------+--------+------------+---------+
| CJX | 380539 | 0.00262785 | 1 |
| JC | 755322 | 0.00132394 | 1.98487 |
| JX | 672056 | 0.00148797 | 1.76606 |
+--------+--------+------------+---------+
Comparing hash of integers...
Repetitions: 1000 x 200 = 200000
+--------+--------+------------+---------+
| Module | 1/min | min | improve |
+--------+--------+------------+---------+
| CJX | 157604 | 0.00634503 | 1 |
| JC | 388038 | 0.00257707 | 2.46211 |
| JX | 199245 | 0.00501895 | 1.26422 |
+--------+--------+------------+---------+
Comparing hash of Unicode strings...
Repetitions: 1000 x 200 = 200000
+--------+-------------+-------------+---------+
| Module | 1/min | min | improve |
+--------+-------------+-------------+---------+
| CJX | 513127 | 0.00194883 | 1 |
| JC | 1.04831e+06 | 0.000953913 | 2.04299 |
| JX | 808463 | 0.00123692 | 1.57556 |
+--------+-------------+-------------+---------+
Comparing array of floats...
Repetitions: 1000 x 200 = 200000
+--------+--------+------------+---------+
| Module | 1/min | min | improve |
+--------+--------+------------+---------+
| CJX | 136707 | 0.00731492 | 1 |
| JC | 342001 | 0.00292397 | 2.50171 |
| JX | 156961 | 0.00637102 | 1.14816 |
+--------+--------+------------+---------+
Comparing array of ASCII strings...
Repetitions: 1000 x 200 = 200000
+--------+--------+------------+---------+
| Module | 1/min | min | improve |
+--------+--------+------------+---------+
| CJX | 279881 | 0.00357294 | 1 |
| JC | 547059 | 0.00182796 | 1.95461 |
| JX | 487766 | 0.00205016 | 1.74276 |
+--------+--------+------------+---------+
she ate and left absolutely no crumbs, periodt π
π BUGS π
ngl this is the part where we're honest about the flaws. it's giving "we're working on it".
- right now there is genuinely no way to delete object handlers that you set through
objfrom a JSON::Create object. π - there are a few remaining undecided issues floating around about the default object serialization.
- no warning gets printed when you use clashing methods like
boolandobj_handler. not a peep. silence. π - there is a bug in
JSON::Create::PP's handling of non-integer numbers. - the floating point printing loses precision on round trips. π
π HISTORY π
storytime bestie, here's the whole glow-up timeline:
set_fformatgot added in version 0.07.validategot added in version 0.07.fatal_errorsgot added in version 0.10.replace_bad_utf8got added in version 0.12.obj_handlergot added in version 0.13. this version also added loading of the Pure-Perl version of the module,JSON::Create::PP, in case loadingJSON::Createfailed.non_finite_handlergot added in version 0.17.downgrade_utf8got added in version 0.18.- the
Invalid UTF-8 from user routinediagnostic got added in version 0.19. - the
create_json_strictfunction plus thestrictmethods and their associated diagnostics got added in version 0.20. - indentation got added for objects with
indentin version 0.27. - version 0.28 changed up how context-dependent variables are handled β it now uses the numerical part as a JSON number if it's valid, and the string part as a JSON string if it isn't a valid number. go read "Context-dependent variables" for the whole breakdown.
- arguments to
create_jsonandcreate_json_strict, and the methodsset,sortandcmp, got added in version 0.29. - version 0.30 rewrote
setand the related routines in XS, made the module faster, and addedwrite_json. glow up fr fr β¨ - in version 0.31, the method
rungot renamed tocreate.
π Old names π
runβ the methodrunwas renamedcreatein version 0.31. the old name is not deprecated and will keep working indefinitely, so don't panic, your old code is safe. π«Ά
π SEE ALSO π
JSON::Create::PPβ this is the backup module forJSON::Create, written in pure Perl.- RFC 8259 β RFC 8259 "The JavaScript Object Notation (JSON) Data Interchange Format" <https://www.ietf.org/rfc/rfc8259.txt>
- "SEE ALSO" in
JSON::Parseβ pls go check out "SEE ALSO" inJSON::Parsefor the info on JSON specifications and a whole list of other CPAN modules for JSON.
π§ Installing from the github repository π§
experimentally, it's possible to install this module straight from Github. heads up though: you'll also need to install Template and possibly a few other modules too.
πΈ Blog posts πΈ
there are some blog posts about the JSON::Create internals that Perl XS programmers will be into, and they're right here:
- Using a user-defined sort order from XS <http://blogs.perl.org/users/ben_bullock/2020/12/alles-in-ordnung.html>
- The mysterious case of the SVt_PVIV <http://blogs.perl.org/users/ben_bullock/2020/11/the-mysterious-case-of-the-svt-pviv.html>
- JSON::Create now features indentation <http://blogs.perl.org/users/ben_bullock/2020/11/jsoncreate-now-features-indentation.html>
- av_fetch can return NULL <http://blogs.perl.org/users/ben_bullock/2020/02/av-fetch-can-return-null.html>
- Muddled numbers & strings <https://benbullock.substack.com/p/muddled-numbers-and-strings>
- this one relates to the bug dealing with floating point and integer numbers that was found in version 0.33.
π AUTHOR π
Ben Bullock, <benkasminbullock@gmail.com>
π COPYRIGHT & LICENCE π
this package and its associated files are copyright (C) 2015-2026 Ben Bullock.
you can use, copy, modify and redistribute this package and its associated files under the Perl Artistic Licence or the GNU General Public Licence.
the sorting code that cmp uses comes from the FreeBSD source code and is copyright by the Regents of the University of California.
and that's a wrap on the whole page bestie!! π this was JSON::Create(3), from perl v5.42.2, dated 2026-04-07 β go forth and serialize responsibly, ily, mwah π
β¨π¦
π¦ where this page comes from
- fedora 43: perl-JSON-Create 0.36-1.fc43 Β· (GPL-1.0-or-later OR Artistic-1.0-Perl) AND BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms