All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Fix
MultiJson.method(:load)resolving toKernel#loadinstead of the legacy-constant forwarder (#66). The 1.21.0 shim forwarded calls viamethod_missing, butModule#methoddoesn't consultmethod_missing, so libraries that capture decoders asMethodobjects (Sawyer, used by Octokit and Danger) crashed withLoadErrorwhen the captured method tried to interpret the JSON string as a file path. Define an explicit singleton method onMultiJsonfor every public methodMultiJSONexposes soModule#methodfinds the forwarder directly.
Every deprecation introduced here will be removed in 2.0.0. Upgrade to 1.21.0, run your app or test suite with ruby -W:deprecated to surface the warnings, migrate each call site to the new canonical names, then pin ~> 2.0 once 2.0.0 ships.
- Rename the
MultiJsonconstant toMultiJSON(all-caps) to match the project name, Ruby stdlibJSON, and the all-caps treatment of the JSON acronym across other languages. The legacyMultiJsonconstant continues to work as a thin delegator viamethod_missingandconst_missing, soMultiJson.parse(...),MultiJson::Adapters::Oj, andrescue MultiJson::ParseErrorall resolve to theirMultiJSONcounterparts. - Add
MultiJSON.parseandMultiJSON.generateas the new canonical names for the primary parse and generate methods, matching Ruby stdlibJSON.parse/JSON.generate, the JSON spec (RFC 8259), and sister library MultiXml. - Add
MultiJSON.parse_options/MultiJSON.parse_options=andMultiJSON.generate_options/MultiJSON.generate_options=as the new canonical option setters. - Accept
symbolize_names:as the canonical option name matching Ruby stdlib'sJSON.parse(str, symbolize_names: true). The deprecatedsymbolize_keys:option continues to work and emits a one-time warning when passed at any of the three option layers (call-site,MultiJSON.parse_options=, adapterdefaults :load). - Replace the two-adapter
Benchmark.ipssmoke test inbenchmark.rbwith a full adapter comparison matrix (parse+dumpacross nine workloads) and promote it to a top-levelrake benchmarktask. A new--verify-preferenceflag asserts thatMultiJSON::AdapterSelector::ADAPTERSmatches the observed throughput ranking, with a 10% tolerance for adjacent ties; CI runs it on every push so the ordering can't silently drift.
- Reorder
MultiJSON::AdapterSelector::ADAPTERSso the JSON gem is tried beforefast_jsonparser/oj/yajlon MRI and TruffleRuby, matching the throughput ranking in the bundled benchmark suite on Ruby 3.4+. The hash is split per platform so JRuby still prefersjr_jackson. Affects auto-detection only when more than one of those adapters is loaded; explicitly selecting an adapter withMultiJSON.use(:adapter)is unchanged.
- The
MultiJsonconstant in favor ofMultiJSON. MultiJSON.loadin favor ofMultiJSON.parse.MultiJSON.dumpin favor ofMultiJSON.generate.MultiJSON.load_options/MultiJSON.load_options=in favor ofMultiJSON.parse_options/MultiJSON.parse_options=.MultiJSON.dump_options/MultiJSON.dump_options=in favor ofMultiJSON.generate_options/MultiJSON.generate_options=.- The
:symbolize_keysparse option in favor of:symbolize_names.
All deprecated names continue to work and emit a one-time warning on first use. Warnings are tagged with Ruby's :deprecated category, so noisy apps can silence the whole set with Warning[:deprecated] = false and deprecation-aware tooling (ruby -W:deprecated, CI linters) picks them up. The old names will be removed in 2.0.
- Fix
JsonGem#loadraisingParseErroron ASCII-8BIT strings that contain valid UTF-8 bytes (#64). Ruby HTTP clients tag response bodies as ASCII-8BIT by default; the 1.20.0 change fromforce_encodingtoencodebroke the dominant real-world case by trying to transcode each byte individually. Switch back toforce_encodingfollowed by avalid_encoding?guard so genuinely invalid byte sequences still surface asParseError.
- Validate custom adapters during
MultiJson.useandMultiJson.load/dumpwith an:adapteroption, raisingMultiJson::AdapterErrorimmediately if the adapter does not respond to.load,.dump, or define aParseErrorconstant. - Validate
OptionsCache.max_cache_size=to rejectnil, zero, negative, and non-integer values with a clearArgumentError. - Expand the benchmark suite (
benchmark.rb) into a full adapter comparison matrix covering load, dump, and round-trip across small, medium, and large payloads in both object-heavy and array-heavy shapes.
- Surface parse error locations as
error.lineanderror.columnonMultiJson::ParseError, extracted from the underlying adapter's message for adapters that include one (Oj, the json gem). - Make
MultiJson::OptionsCache.max_cache_sizeconfigurable so applications that generate many distinct option hashes can raise the cache ceiling at runtime. - Add YARD documentation for the
Adaptersmodule andParseErrorconstants. - Document public API methods as
@api publicsoload,dump,use,with_adapter,current_adapter,adapter,load_options, anddump_optionsappear in generated docs. - Type-check the
Yajl,JrJackson, andGsonadapter wrappers under Steep, with stubbed RBS sigs for the underlying libraries living insig/external_libraries.rbs. - Add Ruby 4.0 to the CI matrix.
- Add workflow badges for linter, mutant, steep, and docs.
- Add a
# frozen_string_literal: truemagic comment to every Ruby file inlib/andtest/, enforced byStyle/FrozenStringLiteralComment. - Collect the five process-wide mutexes into a new
MultiJson::Concurrencymodule, collapsed into a singleConcurrency.synchronize(name, &block)method with private constants. - Add a
deprecate_alias/deprecate_methodDSL inlib/multi_json/deprecated.rbso adding or removing a deprecation is a one-liner. - Memoize the per-adapter
ParseErrorlookup inMultiJson.parse_error_class_forso the constant resolution runs at most once per adapter.
- Split the gem into
rubyandjavaplatform variants: thejavavariant addsconcurrent-ruby ~> 1.2as a runtime dependency and ships thegsonandjr_jacksonadapters; therubyvariant has no runtime dependencies and ships the MRI-only adapters. - Make
with_adapteroverrides fiber-local so concurrent fibers and threads each observe their own adapter without racing on a shared module variable. - Raise
MultiJson::ParseErroron invalid UTF-8 in thejson_gemadapter instead of silently reinterpreting bytes withforce_encoding. - Warn once for deprecated method aliases:
decode,encode,engine,engine=,default_engine, andwith_enginenow emit a one-time deprecation warning on first call. - Emit deprecation warnings only once per process for
default_options,default_options=,cached_options, andreset_cached_options!. - Include the original exception's class name in
MultiJson::AdapterError.build's formatted message. - Walk the superclass chain in
Adapter.default_load_options/default_dump_optionsinstead of copying at inheritance time, so a parent callingdefaults :load, ...after a subclass has been defined now propagates. - Replace
(...)argument forwarding inMultiJson::Optionswith explicit*argsso the signatures are self-documenting. - Reorganize
lib/multi_json.rbinto clearer sections and document why both themodule_functionand singleton-only definition patterns coexist. - Restructure
OptionsCachebackend selection so MRI and JRuby execute the same physicalrequire_relativeline, restoring JRuby's line coverage threshold to 100%. - Unify
LOADED_ADAPTER_DETECTORSandREQUIREMENT_MAPinAdapterSelectorinto a singleADAPTERSsource-of-truth. - Replace the per-adapter
loadedlambdas inAdapterSelector::ADAPTERSwith constant name strings walked throughObject.const_defined?directly. - Extract deprecated public API into
lib/multi_json/deprecated.rb. - Improve
AdapterSelector#load_adapter's error message for unrecognized adapter specs. - Move
Oj#load's:symbolize_keystranslation into a privatetranslate_load_optionshelper. - Drop the
ALIASESconstant inAdapterSelectorin favor of an inlinejrjackson→jr_jacksoncheck. - Drop the
UnannotatedEmptyCollectionSteep diagnostic override.
- Stop mutating cached options in
Oj#load: the adapter previously assignedoptions[:symbol_keys]on the shared cached hash. - Stop mutating cached options in
OjCommon#prepare_dump_options:merge!(PRETTY_STATE_PROTOTYPE)on the cached hash removed:prettyand added prototype keys on every call. - Stop mutating cached options in
JsonGem#load. - Stop resetting
OptionsCachewhenMultiJson.useraises so a faileduse(:nonexistent)no longer discards cached entries. - Hold
@eviction_mutexaroundConcurrentStore#reset's@cache.clearso a JRuby fetcher cannot interleave with a concurrent reset. - Guard
ConcurrentStoreeviction against a TOCTOU race so two concurrent JRuby threads cannot both exceedmax_cache_size. - Restore the mutex around
MutexStore#resetfor TruffleRuby. - Synchronize
warn_deprecation_onceso concurrent fibers and threads cannot double-emit. - Make
MultiJson.use'sOptionsCache.resetand@adapterswap atomic under a mutex. - Make
AdapterSelector#default_adapter's lazy initializer thread-safe. - Make
AdapterSelector#default_adapter_excludingthread-safe. - Make
Optionsdefault_load_options/default_dump_optionsinitializers thread-safe. - Defer the
fast_jsonparseradapter's dump-delegate resolution until the firstdumpcall instead of locking it in at file load time. - Raise a clear
MultiJson::AdapterErrorwhen a custom adapter does not define aParseErrorconstant. - Call
to_hon options to properly handleJSON::Stateobjects. - Fix
TestHelpers.yajl?to check the actualyajl-rubygem name. - Fix Bundler 4.0 permission error in CI.
- Stop requiring the
ojgem from thefast_jsonparseradapter (#63). - Stop relying on
Oj::ParseError's::SyntaxErrorancestor when matching exceptions.
- Remove the vendored
ok_jsonadapter and theConvertibleHashKeyshelper module. - Remove the
MultiJson::REQUIREMENT_MAPlegacy alias. - Drop the dead
JrJacksondump arity branch. - Drop the duplicate
Adapter::EMPTY_OPTIONSconstant. - Drop the redundant
options.except(:adapter)allocation inJsonGem#dump. - Drop Oj 2.x compatibility branch: the Oj adapter now requires Oj
~> 3.0. - Drop support for Ruby 3.0, Ruby 3.1, and JRuby 9.4.
- Avoid allocating an options hash on the
dump/loadhot path by reusing a shared frozen empty hash. - Short-circuit empty input in
Adapter.blank?before falling back to the regex match. - Short-circuit
Adapter.blank?on inputs that start with{or[. - Skip
String#scrubinAdapter.blank?when the input is already valid UTF-8. - Skip the per-call hash merge in
JsonGem#dumpwhenpretty: trueis the only option. - Hoist the
block_given?check inMutexStore#fetchoutside the critical section. - Walk the superclass chain manually in
Adapter.walk_default_optionsinstead of allocating anancestorsarray. - Hoist a shared
Gson::DecoderandGson::Encoderfor the empty-options case. - Forward all merged options through
Yajl#loadinstead of honoring only:symbolize_keys. - Validate the
actionandvaluearguments inAdapter.defaultsat definition time.
- Restore deprecated
encode/decodemethods.
- Fix serialization of ActiveSupport-enhanced objects.
- Fix conflict between JSON gem and ActiveSupport (#222).
- Revert minimum Ruby version requirement.
- Make
json_purean alias ofjson_gem.
- JsonCommon: force encoding to UTF-8, not binary.
- Stop setting defaults in JsonCommon.
- Move repo from @intridea to @sferik.
- Remove NSJSONSerialization.
- Stop referencing
JSON::PRETTY_STATE_PROTOTYPE. - Drop support for Ruby versions < 3.2.
- Improve detection of
json_gemadapter.
- Fix a warning in Ruby 2.7.
- Support Oj 3.x gem.
- Fix missing stdlib
setdependency in Oj adapter.
- Make Oj adapter handle
JSON::ParseErrorcorrectly.
- Renew gem certificate.
- Prevent memory leak in OptionsCache.
- Introduce global options cache to improve performance.
- Only pass one argument to JrJackson when two is not supported.
- Dump method passes options through for JrJackson adapter.
- Make all adapters read IO object before load.
- Explicitly require
stringiofor Gson adapter. - Do not read StringIO object before passing it to JrJackson.
- Performance tweaks.
- Convert indent option to Fixnum before passing to Oj.
- Enable
use_to_jsonoption for Oj adapter by default.
- Remove unused LoadError file.
- Rename
LoadErrortoParseError. - Adapter load failure throws
AdapterErrorinstead ofArgumentError.
- Make Gson adapter explicitly read StringIO object.
- Make JrJackson explicitly read StringIO objects.
- Prevent calling
#downcaseon alias symbols.
- Downcase adapter string name for OS compatibility.
- Let the adapter handle strings with invalid encoding.
- Raise
MultiJson::LoadErroron blank input.
- Explicitly require json gem code even when constant is defined.
- Reorder JrJackson before
json_gem. - Update vendored OkJson to version 43.
- Fix options caching issues.
- Bring back
MultiJson::VERSIONconstant.
- Fix warning
*interpreted as argument prefix. - Remove stdlib warning.
- Cache options for better performance.
- Require
json/extto ensure extension version gets loaded forjson_gem. - Rename JrJackson.
- Prefer JrJackson to JSON gem if present.
- Print a warning if outdated gem versions are used.
- Loosen
required_rubygems_versionfor compatibility with Ubuntu 10.04.
- Rename Jrjackson adapter to JrJackson.
- Implement
jrjackson→jr_jacksonalias for backwards compatibility. - Update vendored OkJson module.
- Fix capitalization of JrJackson class.
- Add
load_options/dump_optionsto MultiJson. - Add JrJackson adapter.
- MultiJson does not modify arguments.
- Enable
quirks_modeby default forjson_gem/json_pureadapters. - Raise
ArgumentErroron bad adapter input.
- Revert "Use
JSON.generateinstead of#to_json".
- Add gson.rb support.
- Add
MultiJson.default_options. - Add
MultiJson.with_adapter.
- Stringify all possible keys for
ok_json. - Use
JSON.generateinstead of#to_json. - Alias
MultiJson::DecodeErrortoMultiJson::LoadError.
- Do not allow Oj or JSON to create symbols by searching for classes.
- Add
MultiJson.with_adaptermethod.
- Stringify all possible keys for
ok_json.
- Allow load/dump of JSON fragments.
- Fix rescue clause for MagLev.
- Remove unnecessary check for string version of options key.
- Explicitly set default adapter when adapter is set to
nilorfalse. - Fix Oj
ParseErrormapping for Oj 1.4.0.
- Allow adapter-specific options to be passed through to Oj.
- Add pretty support to Oj adapter.
- Use
class << selfinstead ofmodule_functionto create aliases.
- Remove deprecation warnings.
- Add ability to use adapter per call.
- Add and deprecate
default_enginemethod.
- Only warn once for each instance a deprecated method is called.
- Implement
load/dump; deprecatedecode/encode. - Rename engines to adapters.
- Add support for Oj.
- NSJSONSerialization support for MacRuby.
- Options can be passed to an engine on encode.
- Set data context to
DecodeErrorexception. - Allow
ok_jsonto fall back toto_json. - Add warning when using
ok_json.
- Array support for
stringify_keys. - Array support for
symbolize_keys.
- Allow encoding of rootless JSON when
ok_jsonis used.
- Correct an issue with
ok_jsonnot being returned as the default engine.
- Only rescue from parsing errors during decoding, not any
StandardError. - Rename
okjsonengine and vendored lib took_json. - Add StringIO support to json gem and
ok_json.
- Remove ActiveSupport::JSON support.
- Trap all JSON decoding errors; raise
MultiJson::DecodeError.
- Fix
default_enginecheck for json gem. - Make requirement mapper an Array to preserve order in Ruby versions < 1.9.