NAME

JSON::Create - Create JSON

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 in the distribution.)

VERSION

This document describes JSON::Create version 0.35, corresponding to git commit ffe5ce4b3304dac8f668133563a276f831966bbe at Fri Jul 16 07:42:12 2021 +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 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 to "downgrade_utf8".

escape_slash option

This corresponds to "escape_slash".

fatal_errors option

This corresponds to "fatal_errors".

indent option

This corresponds to "indent".

no_javascript_safe option

This corresponds to "no_javascript_safe".

non_finite_handler option

This corresponds to "non_finite_handler".

object_handler option

This corresponds to "object_handler".

replace_bad_utf8 option

This corresponds to "replace_bad_utf8".

sort option

This corresponds to "sort".

strict option

This corresponds to "strict".

type_handler option

This corresponds to "type_handler".

unicode_escape_all option

This corresponds to "unicode_escape_all".

unicode_upper option

This corresponds to "unicode_upper".

validate option

This corresponds to "validate".

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 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 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 specification) be escaped with a backslash, so / gets turned into \/. Call this with any false value to make the slash not be escaped (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 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 applied is to add a newline plus indentation after each opening bracket, add the same after each comma, and add the same before each closing bracket. Tabs are used for all indentation. The number of tabs is decided by the number of brackets open.

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 in the distribution.)

Reformatting the indentation

Users who prefer a different style of indentation should easily be able to modify this output to their needs using simple substitutions, for example s/^(\t+)/ " " x length ($1) /gesm; will convert from tabs to two space 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);
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 in the distribution.)

This method was added in version 0.27 of the module.

no_javascript_safe

$jc->no_javascript_safe (1);

If called with a true value, this switches off JavaScript protection in the output JSON. If called with a false value, the JavaScript protection is switched on again.

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 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. The default behaviour of this module is described at "Floating point numbers".

The routine handler is supplied with the non-finite number as its sole argument, and returns one argument, the output JSON.

Using null for infinity and NaN

To always use null in place of the default, supply a function like the following:

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 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 the following:

    $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.

  • Delete the handler with any false value

    To remove the handler, simply 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.

  • Checking the output JSON

    The JSON output by your handler may be checked for validity by switching on validation using "validate". If you do not use 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" but passed 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 have supplied.

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. To have 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 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 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 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 within your callback.

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";
}

produces output

There is no such thing as a funky monkey baby at /usr/home/ben/projects/json-create/examples/exception.pl line 10.

(This example is included as examples/exception.pl in the distribution.)

If you prefer to take over all object handling yourself, there is also "obj_handler".

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.

obj_handler

$jc->obj_handler (\& my_obj_handler);

Supply an object handler. If you supply this, all objects will be handled by your handler. For example, you can replace all objects with 'null' or die if an object is found.

  • Calling convention

    The obj_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 the following:

    $json = &{$jc->{obj_handler}} ($item);

    To pass or return multiple values via the obj_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.

  • Delete the handler with any false value

    To remove the handler, simply call the function without an argument,

    $jc->obj_handler ();

    or with a false argument:

    $jc->obj_handler (0);

    The behaviour then reverts to the default.

  • Checking the output JSON

    The JSON output by your handler may be checked for validity by switching on validation using "validate". If you do not use 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 obj_handler callbacks are not caught by "create" but passed through to the parent. Please see the discussion at "obj" for an example.

Turning various types of object into JSON

Here is an example of handling various types of object 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";

produces output

{
        "CuriousGeorge":{},
        "FunkyKong":0,
        "KingKong":1,
        "PeterTork":"Monkees"
}

{
        "CuriousGeorge":null,
        "FunkyKong":false,
        "KingKong":true,
        "PeterTork":"Monkees"
}

{
        "CuriousGeorge":{},
        "FunkyKong":0,
        "KingKong":1,
        "PeterTork":"Monkees"
}

(This example is included as examples/obj-handler.pl in the distribution.)

Turning everything into JSON

Here is an example of a "try harder" routine which does something like the JSON module does, by looking for methods on all 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";

produces 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 example is included as examples/try-harder.pl in the distribution.)

This obj_handler overrides whatever you have set with "bool" or "obj". Currently, it does not print a warning about this. See "BUGS". The routine you use to handle objects may be the same as the routine you use to handle types. See "type_handler". For more details about the callbacks, see "obj".

This method was added in version 0.13 of the module.

replace_bad_utf8

$jc->replace_bad_utf8 (1);

Replace invalid UTF-8 in the inputs with the Unicode replacement character U+FFFD, rather than produce the warning or error "Invalid UTF-8".

If replace_bad_utf8 is used on input containing only strings not marked as character strings, and bad UTF-8 is found, JSON::Create marks the output as a character string. Otherwise the replacement character itself is just a series of broken bytes. This behaviour can be altered with the method "downgrade_utf8".

This method was 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. This is validated and a warning printed if the format cannot be used. The format is also restricted to a maximum length to prevent buffer overflows within the module.

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";

produces 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 example is included as examples/set-fformat.pl in the distribution.)

This method was added in version 0.07 of the module.

sort

$jc->sort (1);

Sort hash keys. The default is to use Perl's string sorting. Use "cmp" to supply your own sorting routine. This does not affect the order of array elements, only hash keys.

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);

produces output

{
        "animals":{
                "elephant":"🐘",
                "goat":"🐐",
                "kingkong":"🦍"
        },
        "baka":{
                "あ":"ほ",
                "ば":"か",
                "ま":"ぬけ"
        },
        "fruit":{
                "grape":"🍇",
                "melon":"🍈",
                "watermelon":"🍉"
        },
        "moons":{
                "🌑":0,
                "🌒":1,
                "🌓":2,
                "🌔":3,
                "🌕":4,
                "🌖":5,
                "🌗":6,
                "🌘":7
        }
}

(This example is included as examples/sort.pl in the distribution.)

This method was added in version 0.29 of the module.

type_handler

$jc->type_handler (sub {return 'null'});

By default, when JSON::Create encounters a variable of a type which it doesn't know what to do with, such as a glob or code reference, it prints a warning and returns an undefined value. See "Code, regexes, and other references". The method type_handler sets up a callback which is called when a variable of an unhandled type is found in the input. For example, to put the JSON literal null in the output when a reference to a variable of an unhandled type is encountered, rather than print an error, the above example will do it.

  • Calling convention

    The type_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 the following:

    $json = &{$jc->{type_handler}} ($item);

    To pass or return multiple values via the type_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.

  • Delete the handler with any false value

    To remove the handler, simply call the function without an argument,

    $jc->type_handler ();

    or with a false argument:

    $jc->type_handler (0);

    The behaviour then reverts to the default.

  • Checking the output JSON

    The JSON output by your handler may be checked for validity by switching on validation using "validate". If you do not use 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 type_handler callbacks are not caught by "create" but passed through to the parent. Please 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 in the distribution.)

If the "strict" option is chosen, this method is also passed scalar references.

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 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 = '赤ブöAↂϪ';
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

"赤ブöAↂϪ"
"\u8d64\u30d6\u00f6\uff21\u2182\u03ea"
"\u8D64\u30D6\u00F6\uFF21\u2182\u03EA"
"赤ブöAↂϪ"

(This example is included as 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 = '赤ブöAↂϪ';
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

"赤ブöAↂϪ"
"\u8d64\u30d6\u00f6\uff21\u2182\u03ea"
"\u8D64\u30D6\u00F6\uFF21\u2182\u03EA"
"赤ブöAↂϪ"

(This example is included as 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. See the 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.

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 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 in the distribution.)

Arrays

Arrays are converted to JSON arrays. The order of elements of the array is left unchanged.

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 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 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
        ]
}

(This example is included as examples/nested.pl in the distribution.)

Scalars

Non-reference Perl scalars are converted to JSON strings or numbers, depending on what Perl thinks they contain.

Strings

As far as possible, strings are written as they are to the JSON.

JSON is Unicode, so all output is 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. This behaviour can be altered 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".)

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.

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 \".

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 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").

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.

"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 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 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 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.)

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.

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.

"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".

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';

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.

UNICODE HANDLING

This section details JSON::Create's handling of Unicode within strings. This involves the distinction between two things with confusingly similar names, Perl character strings, utf8, and the Unicode encoding UTF-8.

UTF-8 only

JSON::Create only consumes and produces the UTF-8 encoding of Unicode. If you need a different encoding, please use the Encode module to encode the output.

Input strings must be UTF-8

All strings within the input must be UTF-8 encoded. This does not mean that the strings must be Perl character strings (Perl's utf8), it means that input strings must be valid UTF-8. Input strings can be either Perl character strings or bytes, but in either case the bytes of the string must be valid UTF-8.

To illustrate this, examine the following example:

use JSON::Create 'create_json';
use utf8;
$| = 1;
print create_json ('赤ブöAↂϪ'), "\n";
no utf8;
binmode STDOUT, ":raw";
print create_json ('赤ブöAↂϪ'), "\n";
print create_json ("\x99\xff\x10"), "\n";

produces output

"赤ブöAↂϪ"
"赤ブöAↂϪ"
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 in the distribution.)

The point here is that the UTF-8 validation is carried out regardless of whether Perl thinks that the input string is "utf8". The string in the third call to "create_json" is not marked as utf8 by Perl but still fails as invalid UTF-8.

JSON::Create's insistence on UTF-8 within input strings is related to "Unicode upgrades are not done according to Perl conventions".

Output is valid UTF-8

All of the output of either the function "create_json" or the method "create" is valid UTF-8. This does not mean that output strings are marked as Perl character strings (utf8), it means that the output has been validated as UTF-8.

There is one exception to this. In the case of 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", JSON::Create validates the entire output as UTF-8, as described in "UTF-8 validation of user-supplied JSON".

Unicode upgrades are not done according to Perl conventions

If a single string anywhere in the input is a Perl character string, in other words marked as utf8, the entire output string is marked as a Perl character string, utf8, without altering the non-utf8 bytes. 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 combining the two, it is illegal to treat either of these as bytes, but instead they must both be treated as numbers. To illustrate this, here is the behaviour of JSON contrasted with JSON::Create:

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";

produces output

{"x":"かきくけこ","y":"さしすせそ"}
{"x":"かきくけこ","y":"さしすせそ"}

(This example is included as examples/json-unicode.pl in the distribution.)

The Perl convention is that if a non-utf8 string and a utf8 string are combined, they should be combined as JSON does it, by treating each byte of the non-utf8 string as if it is a single Unicode code point, and writing equivalent UTF-8 bytes for that code point into the output. JSON::Create does a different thing, which is to insist 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.

This example 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";

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 in the distribution.)

Using replace_bad_utf8 may cause a utf8 upgrade

Please see the discussion under "replace_bad_utf8".

UTF-8 validation of user-supplied JSON

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", the entire output string has to be validated as UTF-8, to prevent a loophole where a string containing non-UTF-8 compliant bytes could get upgraded to a character string (utf8).

In this case, if invalid UTF-8 is detected, the diagnostic "Invalid UTF-8 from user routine" is printed, and the undefined value returned. Since the check is applied to the final output JSON, there is no information about which routine was at fault, so to get a more specific diagnosis, please switch on "validate".

Here is 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 => 'ぶー'});

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 in the distribution.)

DIAGNOSTICS

All diagnostics are warnings by default. This behaviour can be altered with the method "fatal_errors".

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".

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.

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 with "create_json_strict" and the "strict" method.

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 with "create_json_strict" and the "strict" method.

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 with "create_json_strict" and the "strict" method.

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

There is a benchmarking script in bench/bench.pl which compares the performance of the module with JSON::XS and Cpanel::JSON::XS. Outputs look like this, where the "improve" column is the improvement in speed of the fastest module compared to the slowest:

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 |
+--------+--------+------------+---------+

BUGS

There is currently no way to delete object handlers set via "obj" from a JSON::Create object.

There are a few remaining undecided issues around the default object serialization.

No warning is printed when the user uses clashing methods like "bool" and "obj_handler".

There is a bug in JSON::Create::PP's handling of non-integer numbers.

The floating point printing loses precision on round trips.

HISTORY

"set_fformat" was added in version 0.07.

"validate" was added in version 0.07.

"fatal_errors" was added in version 0.10.

"replace_bad_utf8" was added in version 0.12.

"obj_handler" was added in version 0.13. This version also added loading of the Pure-Perl version of the module, JSON::Create::PP, if the loading of JSON::Create failed.

"non_finite_handler" was added in version 0.17.

"downgrade_utf8" was added in version 0.18.

The "Invalid UTF-8 from user routine" diagnostic was added in version 0.19.

The "create_json_strict" function and "strict" methods and associated diagnostics were added in version 0.20.

Indentation was added for objects with "indent" in version 0.27.

Version 0.28 altered the handling of context-dependent variables to use the numerical part as a JSON number if valid, and the string part as a JSON string if not a valid number. See "Context-dependent variables" for all the details.

Arguments to "create_json" and "create_json_strict", and the methods "set", "sort" and "cmp" were added in version 0.29.

Version 0.30 rewrote "set" and related routines in XS and increased the speed of the module, and added "write_json".

In version 0.31, the method "run" was renamed "create".

Old names

run

The method run was renamed "create" in version 0.31. The old name is not deprecated and will continue to work indefinitely.

SEE ALSO

JSON::Create::PP

This is a backup module for JSON::Create in pure Perl.

RFC 8259

RFC 8259 "The JavaScript Object Notation (JSON) Data Interchange Format"

"SEE ALSO" in JSON::Parse

Please refer to "SEE ALSO" in JSON::Parse for information on the specifications for JSON and a list of other CPAN modules for JSON.

Installing from the github repository

Experimentally, it is possible to install this module from Github. You will also need to install Template and possibly some other modules.

Blog posts

There are some blog posts about the JSON::Create internals of interest to Perl XS programmers here:

Using a user-defined sort order from XS
The mysterious case of the SVt_PVIV
JSON::Create now features indentation
av_fetch can return NULL
Muddled numbers & strings

This relates to the bug dealing with floating point and integer numbers found in version 0.33.

AUTHOR

Ben Bullock, <bkb@cpan.org>

COPYRIGHT & LICENCE

This package and associated files are copyright (C) 2015-2021 Ben Bullock.

You can use, copy, modify and redistribute this package and associated files under the Perl Artistic Licence or the GNU General Public Licence.

The sorting code used by "cmp" comes from the FreeBSD source code and is copyright by the Regents of the University of California.