--- /dev/null
+package JSON::MaybeXS;
+
+use strict;
+use warnings FATAL => 'all';
+use base qw(Exporter);
+
+BEGIN {
+ our $JSON_Class;
+
+ our @err;
+
+ if (eval { require Cpanel::JSON::XS; 1; }) {
+ $JSON_Class = 'Cpanel::JSON::XS';
+ } else {
+ push @err, "Error loading Cpanel::JSON::XS: $@";
+ if (eval { require JSON::PP; 1; }) {
+ $JSON_Class = 'JSON::PP';
+ } else {
+ push @err, "Error loading JSON::PP: $@";
+ }
+ }
+ unless ($JSON_Class) {
+ die join("\n", "Couldn't load a JSON module:", @err);
+ }
+ $JSON_Class->import(qw(encode_json decode_json));
+}
+
+our @EXPORT = qw(encode_json decode_json JSON);
+
+sub JSON () { our $JSON_Class }
+
+1;
--- /dev/null
+use strict;
+use warnings FATAL => 'all';
+use Test::Without::Module 'Cpanel::JSON::XS';
+use Test::Without::Module 'JSON::PP';
+use Test::More;
+
+ok(!eval { require JSON::MaybeXS; 1 }, 'Class failed to load');
+
+# Test::Without::Module always causes 'did not return a true value' errors
+
+like(
+ $@, qr{Cpanel/JSON/XS.pm did not.*JSON/PP.pm did not}s,
+ 'Both errors reported'
+);
+
+done_testing;
--- /dev/null
+use strict;
+use warnings FATAL => 'all';
+use Test::Without::Module 'Cpanel::JSON::XS';
+use if !do { require JSON::PP; 1; }, 'Test::More', skip_all => 'No JSON::PP';
+use Test::More;
+use JSON::MaybeXS;
+
+is(JSON, 'JSON::PP', 'Correct JSON class');
+
+is(
+ \&encode_json, \&JSON::PP::encode_json,
+ 'Correct encode_json function'
+);
+
+is(
+ \&decode_json, \&JSON::PP::decode_json,
+ 'Correct encode_json function'
+);
+
+done_testing;
--- /dev/null
+use strict;
+use warnings FATAL => 'all';
+use if !do { require Cpanel::JSON::XS; 1; }, 'Test::More', skip_all => 'No Cpanel::JSON::XS';
+use Test::More;
+use JSON::MaybeXS;
+
+is(JSON, 'Cpanel::JSON::XS', 'Correct JSON class');
+
+is(
+ \&encode_json, \&Cpanel::JSON::XS::encode_json,
+ 'Correct encode_json function'
+);
+
+is(
+ \&decode_json, \&Cpanel::JSON::XS::decode_json,
+ 'Correct encode_json function'
+);
+
+done_testing;