Module:...ic::JSON(3)

πŸ“¦ version 1.1.3, in alpine 3.24

πŸ’– NAME πŸ’–

Module::Generic::JSON β€” a thin and reliable wrapper around JSON, bestie. That's the whole vibe: it's JSON but with manners ✨

(also hi, this is from the Module:...ic::JSON(3) manual page, ur welcome 🫢)


✨ SYNOPSIS ✨

Like, here's the basic move:

use Module::Generic::JSON;
my $j = Module::Generic::JSON->new(
    utf8         => 1,
    pretty       => 1,
    canonical    => 1,
    relaxed      => 1,
    allow_nonref => 1,
) || die( Module::Generic::JSON->error );
$j->encode( $some_ref ) || die( $j->error );

Or, if you're feeling the chainable vibe:

my $j = Module::Generic::JSON->new;
$j->utf8->pretty->canonical->relaxed->allow_nonref->encode( $some_ref ) ||
    die( $j->error );

Or β€” and this is the simplest one, lowkey iconic:

use Module::Generic::JSON qw( new_json );
my $j = new_json(
    utf8         => 1,
    pretty       => 1,
    canonical    => 1,
    relaxed      => 1,
    allow_nonref => 1,
) || die( Module::Generic::JSON->error );
$j->encode( $some_ref ) || die( $j->error );

πŸŽ€ VERSION πŸŽ€

v0.2.2

🌸 DESCRIPTION 🌸

Okay so, this is a thin and reliable wrapper around the otherwise excellent JSON class. Like, JSON ate, no notes β€” but this wrapper adds some seriously good value:

  • You can set all the JSON properties right at object instantiation. πŸ’…

As mentioned in the synopsis, you can do:

my $j = Module::Generic::JSON->new(
    utf8         => 1,
    pretty       => 1,
    canonical    => 1,
    relaxed      => 1,
    allow_nonref => 1,
) || die( Module::Generic::JSON->error );

instead of:

my $j = Module::Generic::JSON->new;
$j = $j->utf8->pretty->canonical->relaxed->allow_nonref;
  • No fatal exception that would kill your process inadvertently. 🫢

This is so important in a web application, because you do not want some module just unaliving your process mid-request, fr fr. You want the exception handled gracefully.

So instead of having to do this whole thing:

local $@;
my $ref = eval{ $j->decode( $payload ) };
if( $@ )
{
    # Like returning a 500 or maybe 400 HTTP error
    bailout_gracefully( $@ );
}

you can simply do:

my $ref = $j->decode( $payload ) || bailout_gracefully( $j->error );
  • Upon error, it returns an exception object. 😭✨
  • All method calls are passed through to JSON, and any exception is caught, and handled properly for you. Not me doing all the emotional labour for you πŸ’€

For class functions too, you can execute them safely and catch error, if any, by calling Module::Generic::JSON->error, so for example:

decode_json( $some_data ) || die( Module::Generic::JSON->error );

πŸ”₯ CONSTRUCTOR πŸ”₯

new

This takes an hash or hash reference of options and returns a new Module::Generic::JSON object. The options must be supported by JSON. On error, sets an error object and returns undef in scalar context or an empty list in list context:

my $j = Module::Generic::JSON->new( utf8 => 1, pretty => 1 ) ||
    die( Module::Generic::JSON->error );

🌈 METHODS 🌈

See the documentation for the module JSON for more information, but below are the known methods supported by JSON β€” yes, all of them, we're listing every single one, nobody gets left out πŸ‘‘

  • allow_blessed
  • allow_nonref
  • allow_tags
  • allow_unknown
  • ascii
  • backend
  • boolean
  • boolean_values
  • canonical
  • convert_blessed
  • decode β€” decodes a JSON string and returns the resulting Perl data structure. On error, sets an error object and returns undef in scalar context or an empty list in list context:
my $data = $j->decode( '{"a":1}' ) || die( $j->error );
  • decode_prefix
  • encode β€” encodes a Perl data structure into a JSON string. On error, sets an error object and returns undef in scalar context or an empty list in list context:
my $json_str = $j->encode( { a => 1 } ) || die( $j->error );
  • filter_json_object
  • filter_json_single_key_object
  • indent
  • is_pp
  • is_xs
  • latin1
  • max_depth
  • max_size
  • pretty
  • property
  • relaxed
  • space_after
  • space_before
  • utf8

⭐ CLASS FUNCTIONS ⭐

decode_json

Decodes a JSON string and returns the resulting Perl data structure. On error, sets an error object and returns undef in scalar context or an empty list in list context:

my $data = decode_json( '{"a":1}' ) || die( Module::Generic::JSON->error );

encode_json

Encodes a Perl data structure into a JSON string. On error, sets an error object and returns undef in scalar context or an empty list in list context:

my $json_str = encode_json( { a => 1 } ) || die( Module::Generic::JSON->error );

from_json

Decodes a JSON string with optional configuration options. Takes a JSON string and an optional hash reference of options (passed to new). On error, sets an error object and returns undef in scalar context or an empty list in list context:

my $data = from_json( '{"a":1}', { utf8 => 1 } ) || die( Module::Generic::JSON->error );

to_json

Encodes a Perl data structure with optional configuration options. Takes a Perl data structure and an optional hash reference of options (passed to new). On error, sets an error object and returns undef in scalar context or an empty list in list context:

my $json_str = to_json( { a => 1 }, { pretty => 1 } ) || die( Module::Generic::JSON->error );

πŸ¦‹ SERIALISATION πŸ¦‹

Module::Generic::JSON inherits serialisation methods from Module::Generic. The following subroutines are implemented: FREEZE, THAW, STORABLE_freeze, and STORABLE_thaw. See Module::Generic for details. 🧚


πŸ’œ THREAD-SAFETY πŸ’œ

Module::Generic::JSON is thread-safe for all operations, because it operates on per-object state and avoids the thread-safety issues present in the underlying JSON module. That's the glow-up, bestie ✨

Key considerations for thread-safety:

  • Shared Variables

There are no shared variables that are modified at runtime in Module::Generic::JSON. The global $DEBUG variable (inherited from Module::Generic) is typically set before threads are created, and it is the user's responsibility to ensure thread-safety if modified at runtime:

use threads;
local $Module::Generic::JSON::DEBUG = 0; # Set before threads
my @threads = map
{
    threads->create(sub
    {
        my $json = Module::Generic::JSON->new( utf8 => 1 );
        $json->encode( { a => 1 } ); # Thread-safe
    });
} 1..5;
$_->join for( @threads );

Note that the JSON module uses a global $JSON variable for functions like encode_json and decode_json, which can lead to thread-safety issues if modified at runtime. Module::Generic::JSON avoids this by creating a new object instance for each call to decode_json and encode_json, ensuring thread isolation. Not it being chaotic πŸ’€

  • Object State

The underlying JSON object is stored per-object, ensuring thread isolation:

use threads;
my @threads = map
{
    threads->create(sub
    {
        my $json = Module::Generic::JSON->new( utf8 => 1 );
        $json->encode( { tid => threads->tid } ); # Thread-safe
    });
} 1..5;
$_->join for( @threads );
  • Class Functions

Class functions like decode_json and encode_json create a new object per call, ensuring thread isolation:

use threads;
my @threads = map
{
    threads->create(sub
    {
        my $data = decode_json( '{"a":1}' ); # Thread-safe
    });
} 1..5;
$_->join for( @threads );
  • External Libraries

The underlying JSON module (both JSON::XS and JSON::PP) is thread-safe for object methods, as it operates on per-object state. However, its class functions (e.g., encode_json, decode_json) are not thread-safe due to the use of a global $JSON variable. Module::Generic::JSON mitigates this by always creating a new instance for such calls.

  • Serialisation

Serialisation methods (FREEZE, THAW) operate on per-object state, making them thread-safe.

For debugging in threaded environments (depending on your Operating System):

ls -l /proc/$$/fd  # List open file descriptors
🫢 That /proc/$$/fd trick is Linux-coded β€” it's literally listed as "depending on your Operating System", so don't come for me if your OS is different.

πŸ‘‘ AUTHOR πŸ‘‘

Jacques Deguest <jack@deguest.jp>


🌟 SEE ALSO 🌟

JSON, Module::Generic::Exception


Copyright(c) 2025 DEGUEST Pte. Ltd.

All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


okay that's the whole page, periodt πŸ’… tysm for reading, and remember: decode_json( $some_data ) || die( Module::Generic::JSON->error ); is a lifestyle.

mwah πŸŽ€ this was Module::Generic::JSON, perl v5.42.2, dated 2026-02-15 β€” go slay some JSON, bestie 🌸

πŸ“¦ where this page comes from