intridea / multi_json Goto Github PK
View Code? Open in Web Editor NEWA generic swappable back-end for JSON handling.
Home Page: http://rdoc.info/projects/intridea/multi_json
License: MIT License
A generic swappable back-end for JSON handling.
Home Page: http://rdoc.info/projects/intridea/multi_json
License: MIT License
I can't run the latest as version as it pollutes logs.
I'd like to be able to quote/escape strings to JavaScript string literals. Using MultiJson.encode works for this use case depending on which JSON library is used. Other JSON libraries work fine (json
, json_pure
, yajl
), but okjson
refuses to encode a string as it'd result in invalid JSON (afaik).
For example, MultiJson.encode("foo")
returns "\"foo\""
when json gem is used exception is thrown: OkJson::Error: root value must be an Array or a Hash
.
There are two possible paths to solve this issue. okjson
is able encode invalid JSON by using OkJson.valenc
for encoding instead of OkJson.encode
. If relying on non-standard behavior is not wanted, perhaps string quoting could be exposed as a separate method and similar constraint regarding type of root object could be added to MultiJson.encode
.
The adapter for the oj
does not support the :pretty
option properly — oj uses a indent
option.
require 'multi_json'
require 'oj'
puts "Not pretty...",
MultiJson.dump( {a: { b: 'c' }}, pretty: true ),
"", "Pretty!",
MultiJson.dump( {a: { b: 'c' }}, indent: 2 )
Either the oj
gem could add the pretty
option, or MultiJson could wrap the incompatible setting in oj.rb
.
I ran into this today after a bundle update from Rails 3.2.11 to 3.2.12:
ActionView::Template::Error (undefined method `dump' for ActiveSupport::JSON:Module
(in /home/me/myapp/app/assets/javascripts/application.js.coffee)):
1: <head>
2: <title><%= title %></title>
3: <%= stylesheet_link_tag 'application' %>
4: <%= javascript_include_tag 'application' %>
Which, of course doesn't make much sense because there's no ruby in the coffee.
I tracked it down to the multi_json gem here:
# Encodes a Ruby object as JSON.
def dump(object, options={})
options = default_options.merge(options)
adapter = current_adapter(options)
adapter.dump(object, options) # <= right there!
end
When in the debugger, the adapter
became the ActiveSupport::JSON:Module
, which doesn't define a dump
method. I don't think this is even the right object for adapter
to be holding.
Downgrading from multi_json 1.6.0 to the old 1.5.1 solves the issue.
JSON is a great format for information transport, but its lack of comments makes it bad for configuration files. The JSON+Comments spec aims to fix that. I would like to add an optional mixin (e.g. require "multi_json/minus_comments"
) that will strip out comments from input before passing it on to the underlying decoder.
Is anyone for or against? Any suggestions, opinions, or qualms?
Currently there is no way of specifying global configuration for all calls to load() or dump(). It'd be nice to have that, as then we could do something like:
MultiJson.default_options[:max_nesting] = 200
... in our Rails 3 app.
Sorry to bother you again but it seems that the last Travis run was 7 months ago: https://travis-ci.org/intridea/multi_json
Is it intended ?
NaN is not part of the json standard, but it was emitted by some json libs, probably even multi_json. It was also parsed through multi_json but not any more.
Here is an example:
{"ns":"scottyapp.test","count":0,"size":0,"avgObjSize":NaN,"storageSize":8192,"numExtents":1,"nindexes":1,"lastExtentSize":8192,"paddingFactor":1.0,"flags":1,"totalIndexSize":8192,"indexSizes":{"id":8192},"ok":1.0}
Which results in
MultiJson::DecodeError:
196: unexpected token at 'NaN,"storageSize":8192,"numExtents":1,"nindexes":1,"lastExtentSize":8192,"paddingFactor":1.0,"flags":1,"totalIndexSize":8192,"indexSizes":{"_id_":8192},"ok":1.0}'
Not sure if this is something that should be fixed or not, just wanted to raise the issue here.
MultiJson.encode Time.zone.now throws an error:
Failure/Error: MultiJson.encode Time.zone.now
OkJson::Error:
cannot encode ActiveSupport::TimeWithZone: Tue, 26 Jul 2011 01:00:37 UTC +00:00
to repro this, just create a new Rails 3 app, add
gem 'rspec-rails'
gem 'multi_json'
to Gemfile
then run
> bundle
> Rails g rspec:install
then write a simple spec like this
require 'spec_helper'
describe "MultiJson" do
it "should be able to encode TiemWithZone" do
MultiJson.encode Time.zone.now # this fails!
end
end
However if you launch rails console, and execute the same statement, it will work.
Edit: looking into the adapter implementations, it becomes clear that the parameter for the load method can indeed be a stream. The docs should make this clear, though.
There is still an unrelated issue, here:
Currently in Rails, the body data of a request (e.g. POST) will be ignored if the content length is not set or zero (see file params_parser.rb. In other words, there is no way to have a client send JSON with a POST request whose Transfer-Encoding is set to Chunked.
Now, sine the JSON decoders would be able to handle a stream as input, can this be changed in Rails? That is, it seems not required to discard the body data of a (POST) request (aka parameters) when the header Content-Length is not set - or the length evaluates to zero.
It looks like the specs accidentally got broken in multi_json 1.0.3 in a commit that otherwise just does a lot of textual cleanup. SHA d830026
As far as I can tell the situation with yajl not being available on jruby has not changed, and specs fail for me with jruby.
There seems to be an error in json_common.rb, which we found out due to a bug in the ActiveSupport::JSON module.
ActiveSupport::JSON does not encode 16+ bits characters, but chops them off – as we found out the other day.
JSON.generate however, does not have this bug and does the job well.
The point is that in json_common.rb on line 7, the library uses JSON.parse, but on line 11, the .to_json uses ActiveSupport::JSON, which is another library that contains that bug.
Shouldn't the library use JSON.generate here?
update: this issue became just a collection of jruby, encoding, json and related gems issues.
this test don't pass when running on jruby 1.6.4 @ 1.9 mode.
it "should decode json even with special chars" do
MultiJson.decode({:message => "á"}.to_json)['message'].should eq "á"
end
I'm currently investigating it with @headius (here https://jira.codehaus.org/browse/JRUBY-6033) but registered here in case someone find the same problem or if you guys think it could be a problem with multi_json or one of its engines.
The current stable version of 1.5.1 doesn´t allow to pass create_addition => true as an option (https://github.com/intridea/multi_json/blob/1-5-stable/lib/multi_json/adapters/json_common.rb#L7). This breaks gems like Couchrest (couchrest/couchrest#92).
The current master fixes this problem (https://github.com/intridea/multi_json/blob/master/lib/multi_json/adapters/json_common.rb#L15). Please release it as soon as possible.
Thx
I getting this error when I do:
>> require 'multi_json'
=> true
>> require 'multi_json/version'
=> true
>> MultiJson::VERSION
=> "1.3.3"
>> MultiJson.encode('a')
NoMethodError: undefined method `encode' for MultiJson:Module
from (irb):7
from /Users/rafaelmfranca/.rbenv/versions/1.9.3-p125/bin/irb:12:in `<main>'
>> MultiJson.dump('a')
=> "\"a\""
I saw the diff and seems like you only aliased encode as dump, but it is not working.
Clients of MultiJson should be able to easily extract the string that was attempting to be parsed to JSON representation as some application do not have direct access to that data (e.g. a client of the twitter gem that uses MultiJson cannot get the response.body data without some metaprogramming).
Pull request coming right up (RSpec examples and fix has been added locally already).
Hi,
After upgrading multi_json to 1.6.1
from 1.5.1
in a Rails 3.2.11
app, I started getting the following error:
NameError: uninitialized constant ActiveSupport::JSON::ParseError
from /usr/local/rvm/gems/ruby-1.9.3-p194@videodigmcms/gems/multi_json-1.6.1/lib/multi_json.rb:103:in `rescue in load'
from /usr/local/rvm/gems/ruby-1.9.3-p194@videodigmcms/gems/multi_json-1.6.1/lib/multi_json.rb:101:in `load'
from (irb):4
from /usr/local/rvm/gems/ruby-1.9.3-p194@videodigmcms/gems/railties-3.2.11/lib/rails/commands/console.rb:47:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p194@videodigmcms/gems/railties-3.2.11/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p194@videodigmcms/gems/railties-3.2.11/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Reverting back to 1.5.1
fixes it. I am not sure if this is related to #92 or #95, but any ideas would be great. I am not really using multi_json directly, rather I am using ActiveSuppord::JSON.decode
method, which uses multi_json under the hood.
Thanks,
San
ex: Yajl::Encoder.encode(body, :pretty => true, :indent => "\t")
At the moment MultiJson.encode only accepts an object.. simple fix, just add the options hash.
Reported here: rails-api/active_model_serializers#202
>> d = BigDecimal.new('10')
>> JSON.dump(foo: d)
=> "{\"foo\":\"0.1E2\"}"
>> Yajl.dump(foo: d)
=> "{\"foo\":\"0.1E2\"}"
>> Oj.dump(foo: d)
=> "{\":foo\":0.1E2}"
JSON
and Yajl
both encode BigDecimal
instances as string and Oj
as number.
Can MultiJson do something to normalize this across backends ?
Since a few days I get the error "uninitialized constant OkJson::Error" (gem is used in omniauth). Last week it was still works.
Trace:
multi_json (1.0.2) lib/multi_json.rb:50:in`engine='
multi_json (1.0.2) lib/multi_json.rb:10:in `engine'
multi_json (1.0.2) lib/multi_json.rb:66:in`decode'
oa-oauth (0.2.5) lib/omniauth/strategies/facebook.rb:21:in `user_data'
oa-oauth (0.2.5) lib/omniauth/strategies/facebook.rb:63:in`auth_hash'
oa-core (0.2.5) lib/omniauth/strategy.rb:128:in `callback_phase'
oa-oauth (0.2.5) lib/omniauth/strategies/oauth2.rb:78:in`callback_phase'
oa-core (0.2.5) lib/omniauth/strategy.rb:68:in `callback_call'
oa-core (0.2.5) lib/omniauth/strategy.rb:42:in`call!'
oa-core (0.2.5) lib/omniauth/strategy.rb:30:in `call'
oa-core (0.2.5) lib/omniauth/strategy.rb:44:in`call!'
oa-core (0.2.5) lib/omniauth/strategy.rb:30:in `call'
oa-core (0.2.5) lib/omniauth/builder.rb:30:in`call'
warden (1.0.4) lib/warden/manager.rb:35:in `call'
warden (1.0.4) lib/warden/manager.rb:34:in`catch'
warden (1.0.4) lib/warden/manager.rb:34:in `call'
actionpack (3.0.7) lib/action_dispatch/middleware/best_standards_support.rb:17:in`call'
actionpack (3.0.7) lib/action_dispatch/middleware/head.rb:14:in `call'
rack (1.2.2) lib/rack/methodoverride.rb:24:in`call'
actionpack (3.0.7) lib/action_dispatch/middleware/params_parser.rb:21:in `call'
actionpack (3.0.7) lib/action_dispatch/middleware/flash.rb:182:in`call'
actionpack (3.0.7) lib/action_dispatch/middleware/session/abstract_store.rb:149:in `call'
actionpack (3.0.7) lib/action_dispatch/middleware/cookies.rb:302:in`call'
activerecord (3.0.7) lib/active_record/query_cache.rb:32:in `call'
activerecord (3.0.7) lib/active_record/connection_adapters/abstract/query_cache.rb:28:in`cache'
activerecord (3.0.7) lib/active_record/query_cache.rb:12:in `cache'
activerecord (3.0.7) lib/active_record/query_cache.rb:31:in`call'
activerecord (3.0.7) lib/active_record/connection_adapters/abstract/connection_pool.rb:354:in `call'
actionpack (3.0.7) lib/action_dispatch/middleware/callbacks.rb:46:in`call'
activesupport (3.0.7) lib/active_support/callbacks.rb:416:in `_run_call_callbacks'
actionpack (3.0.7) lib/action_dispatch/middleware/callbacks.rb:44:in`call'
rack (1.2.2) lib/rack/sendfile.rb:107:in `call'
actionpack (3.0.7) lib/action_dispatch/middleware/remote_ip.rb:48:in`call'
actionpack (3.0.7) lib/action_dispatch/middleware/show_exceptions.rb:47:in `call'
railties (3.0.7) lib/rails/rack/logger.rb:13:in`call'
rack (1.2.2) lib/rack/runtime.rb:17:in `call'
activesupport (3.0.7) lib/active_support/cache/strategy/local_cache.rb:72:in`call'
rack (1.2.2) lib/rack/lock.rb:11:in `call'
rack (1.2.2) lib/rack/lock.rb:11:in`synchronize'
rack (1.2.2) lib/rack/lock.rb:11:in `call'
actionpack (3.0.7) lib/action_dispatch/middleware/static.rb:30:in`call'
railties (3.0.7) lib/rails/application.rb:168:in `call'
railties (3.0.7) lib/rails/application.rb:77:in`send'
railties (3.0.7) lib/rails/application.rb:77:in `method_missing'
vendor/plugins/heroku-autoscale/lib/heroku/autoscale.rb:26:in`call'
railties (3.0.7) lib/rails/rack/log_tailer.rb:14:in `call'
rack (1.2.2) lib/rack/content_length.rb:13:in`call'
rack (1.2.2) lib/rack/handler/webrick.rb:52:in `service'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/httpserver.rb:104:in`service'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:173:in`start_thread'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:162:in `start'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:162:in`start_thread'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:95:in `start'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:92:in`each'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:92:in `start'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:23:in`start'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/webrick/server.rb:82:in `start'
rack (1.2.2) lib/rack/handler/webrick.rb:13:in`run'
rack (1.2.2) lib/rack/server.rb:213:in `start'
railties (3.0.7) lib/rails/commands/server.rb:65:in`start'
railties (3.0.7) lib/rails/commands.rb:30
railties (3.0.7) lib/rails/commands.rb:27:in `tap'
railties (3.0.7) lib/rails/commands.rb:27
script/rails:6:in`require'
script/rails:6
Small fix that works for me:
ok_json.rb #6: ParseError = ::OkJson::Error unless defined?(::OkJson)
require 'json'
require 'multi_json'
MultiJson.load MultiJson.dump('string')
results in:
MultiJson::DecodeError: 743: unexpected token at '"string"'
from /Users/roman/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/json/common.rb:148:in `parse'
I believe that you have to use JSON.load instead of JSON.parse
This will work as well:
JSON.parse '"string"', quirks_mode: true
This is being seen via various routes (Resque, Rabl https://github.com/defunkt/resque/issues/810)
Downgrading to multi_json 1.5.1 solves the problem. Will investigate more to see why.
NoMethodError: undefined method `key?' for #JSON::Ext::Generator::State:0x000000080d2908
Stack trace:
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activesupport-3.2.11/lib/active_support/core_ext/object/try.rb:36:in `try'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activemodel-3.2.11/lib/active_model/serializers/json.rb:91:in `as_json'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activesupport-3.2.11/lib/active_support/json/encoding.rb:47:in `block in encode'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activesupport-3.2.11/lib/active_support/json/encoding.rb:77:in `check_for_circular_references'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activesupport-3.2.11/lib/active_support/json/encoding.rb:46:in `encode'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activesupport-3.2.11/lib/active_support/json/encoding.rb:31:in `encode'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/activesupport-3.2.11/lib/active_support/core_ext/object/to_json.rb:16:in `to_json'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/json-1.7.7/lib/json/common.rb:223:in `generate'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/json-1.7.7/lib/json/common.rb:223:in `generate'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/multi_json-1.6.0/lib/multi_json/adapters/json_common.rb:10:in `dump'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/rabl-0.7.10/lib/rabl/engine.rb:236:in `format_json'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/rabl-0.7.10/lib/rabl/engine.rb:62:in `to_json'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/rabl-0.7.10/lib/rabl/engine.rb:37:in `block in render'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/rabl-0.7.10/lib/rabl/engine.rb:277:in `cache_results'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/rabl-0.7.10/lib/rabl/engine.rb:37:in `render'
/opt/teamcity-agent/work/caeede80476a904d/vendor/ruby/1.9.1/gems/rabl-0.7.10/lib/rabl/renderer.rb:49:in `render'
If MultiJson implemented pretty_generate, which is a method supported directly by Json/Json-Pure and indirectly by Yajl (by passing :pretty => true to encode), it would allow other libraries that rely on this method the ability to migrate to multi_json. For okjson, the method would simply call encode -- after all prettiness is in the eye of the beholder.
Rails 3.1.5 depends on json 1.6.3. But the multi_json Gemfile depends on 1.4.6.
I use the soulmate gem which depends on the latest version of the multi_json gem.
So I have this trace when I bundle my app:
Bundler could not find compatible versions for gem "json":
In Gemfile:
soulmate (>= 0) ruby depends on
json (~> 1.4.6) ruby
sass-rails (~> 3.1.5) ruby depends on
json (1.6.3)
I already forked Soulmate to fix my bug, but I suspect it is a multi_json relative bug.
As @timanglade said in his talk at GoGaRuCo this year, multi_json has some very poor performance characteristics when used with the built-in implementation. I would like to see the library produce a warning when the default implementation is used.
cc @sferik
Hey guys/gals,
I was going through and fixing deprecated warnings in a couple code bases [1] when @lewinski pointed out that Rails v3.2 is locking down it's MultiJson dependency to '>= 1.0', '< 1.3'
[2]
The original pull request was rails/rails#5861
Should we be locking libraries we want to rails compatible to < 1.3
? I'd like to find a win-win-win solution if we can.
[1] - collectiveidea/json_spec#26 (comment) and jnunemaker/httparty#134
[2] - https://github.com/rails/rails/blob/3-2-stable/activesupport/activesupport.gemspec
MultiJson now sets default options for OJ. This will overwrite configs if they are set on the OJ gem itself. MultiJson should check for existing options on the adapter and reverse_merge its own defaults to avoid changing the expected behavior.
There have been a lot of changes happening to multi_json lately and it's not clear what's changing between releases. 1.3.0 and 1.3.1 were yanked, but no one seems to know why. 1.3.2 changed the API, but few seem to know why. It'd be great if there was a changelog that indicated what changed between releases, caveats, and general info people should know about each release.
MultiJson.decode 'null'
gives me
MultiJson::DecodeError: 757: unexpected token at 'null'
I'm assuming it should be nil (am I assuming correctly?). When null is not alone it gets parsed as expected:
MultiJson.decode '[null]' # => [nil]
MultiJson.adapter says it's :json_gem, but JSON.load('null') works properly. I'm a bit lost with all these json implementations so I'm not even sure I'm filing this issue at proper project :) Any hints on this issue would be very welcome.
You should catch all exceptions from the engines and translate them to common MultiJson exceptions, so that the user can only catch the final exception.
I am receiving this error when calling MultiJson.load "{:aaa => 'bbbb'}"
on version from master branch. I am using this version because of support for default_options
. Dumping works as expected, but loading fails. Btw: As adapter I am using oj
json gem running on MRI 1.9.3p194
.
More details:
.../bundler/gems/multi_json-eafaa81b8c7f/lib/multi_json.rb:98:in `rescue in load'
.../bundler/gems/multi_json-eafaa81b8c7f/lib/multi_json.rb:96:in `load'
There are only two hard problems in Computer Science: cache invalidation and naming things.
I'm proposing that we change the name of the category of things that convert JSON to Ruby objects and Ruby objects to JSON. Right now we call them "engines". I think that name is suboptimal name for a few reasons:
Rails::Application.superclass
in a Rails >= 3 console).I'd offer the following alternatives to "engines", none of which are perfect, but any of which I believe would be an improvement:
MultiJson.use :json_pure
. This solution allows us to avoid actually picking a name (at least at the interface level) and comes from the rich tradition of fill-in-the-blank method names in Ruby, including start_with?
, end_with?
, sort_by
, form_for
, etc.We could also just call them "libraries", but I think that's even more generic (and therefore worse) than "engines".
Or we could stick with "engines".
This is a hardcore breaking change ✊💣 but as long as we're planning to push a backwards-incompatible 2.0 release, we might as well make all the API changes we think will improve the library.
multi_json should support json-jruby and use it preferably on JRuby.
Hello,
I am trying to package multi_json for Fedora, however vendored OkJson is against our policies [1]. Could you please consider removing the bundled OkJson?
[1] http://fedoraproject.org/wiki/Packaging:Guidelines#Duplication_of_system_libraries
Regardless of JSON adapter, the following occurs:
irb(main):006:0> MultiJson.load "{oops"
MultiJson::LoadError: 399: unexpected token at '{oops]'
from /Users/tyson/.rbenv/versions/1.9.3-p327/lib/ruby/gems/1.9.1/gems/json-1.7.7/lib/json/common.rb:155:in `parse'
...
irb(main):007:0> JSON.load("{oops")
JSON::ParserError: 795: unexpected token at '{oops'
This causes a lot of confusion when debugging JSON issues -- you end up trying to figure out where the heck that trailing ]
is coming from.
It is, of course, coming from here: https://github.com/intridea/multi_json/blob/master/lib/multi_json/adapters/json_common.rb#L11
The obvious fix would be to remove the array via string interpolation bit and .first
, but it seems like that's there for a reason. What is that reason?
I've been using Sidekiq and Rufus Scheduler to create a schedule of tasks to run each day for the last year. Today I updated a few gems and my rufus task started crashing after running for a minute or two. After reverting multi_json back to 1.3.7 (the version we used to be on), everything went back to normal. The crash actually caused a segmentation fault and didn't happen in unit tests or locally on a small scale, so it seems that the issue could be a thread safety issue. I didn't save the exception dump, but I could easily make it happen again if that would be useful.
Hi,
Not sure if you're the one publishing/yanking gems, but if it is:
Please don't yank old gem versions, unless there is some security issue motivating it. It causes a lot of broken builds and extra work for everyone using the multi_json gem when they're yanked.
If we implemented dump
and load
to replace encode
and decode
respectively, MultiJSON could be used as a drop-in serializer for ActiveRecord objects.
I also happen to prefer dump
/load
over encode
/decode
because they are more consistent with other standard Ruby serialization libraries including Marshal
, YAML
, and, yes, JSON
.
Obviously, renaming encode
and decode
is a hardcore breaking change ✊ 💣 that will require a major version bump and at least one minor release that supports both methods and contains deprecation warnings. I'd propose a very responsible transition but I believe this is a change worth making.
However, before I start writing code, I'd like to solicit feedback from anyone using this gem.
If you're not familiar with custom coders for serialized attributes in Rails 3.1 (and even if you are), I'd highly recommend watching @tenderlove's 2011 RailsConf keynote, starting around the 16 minute mark (through at least the 23rd minute): http://youtu.be/kWOAHIpmLAI?t=16m
In 3.09 and previous this line of code worked:
ruby-1.9.2=p180 :001 > puts ActiveSupport::JSON.decode("abc".to_json)
=> "abc"
In 3.1.0.rc1 it does not, apparently due to the change to MultiJson:
ruby-1.9.2=p180 :001 > puts ActiveSupport::JSON.decode("abc".to_json)
MultiJson::DecodeError: 706: unexpected token at '"abc"'
from /home/yardboy/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/json/common.rb:146:in `parse'
from /home/yardboy/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/json/common.rb:146:in `parse'
from /home/yardboy/.rvm/gems/ruby-1.9.2-p180/gems/multi_json-1.0.3/lib/multi_json/engines/json_gem.rb:13:in `decode'
from /home/yardboy/.rvm/gems/ruby-1.9.2-p180/gems/multi_json-1.0.3/lib/multi_json.rb:65:in `decode'
from /home/yardboy/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.1.0.rc1/lib/active_support/json/decoding.rb:12:in `decode'
from (irb):1
from /home/yardboy/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.1.0.rc1/lib/rails/commands/console.rb:44:in `start'
from /home/yardboy/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.1.0.rc1/lib/rails/commands/console.rb:8:in `start'
from /home/yardboy/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.1.0.rc1/lib/rails/commands.rb:40:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Is there a reason for why it doesn't work, or is this a bug?
Let's ship it!
gem install multi_json -v '1.3.4'
System.java:-2:in `arraycopy': java.lang.ArrayIndexOutOfBoundsException
from DefaultResolver.java:111:in `makeTime'
from DefaultResolver.java:277:in `create'
from DefaultResolver.java:317:in `handleScalar'
from DefaultResolver.java:435:in `orgHandler'
from DefaultResolver.java:455:in `node_import'
from DefaultResolver$s$1$0$node_import.gen:65535:in `call'
from CachingCallSite.java:137:in `call'
from RubyLoadHandler.java:40:in `handle'
from Parser.java:300:in `addNode'
from DefaultYAMLParser.java:676:in `yyparse'
from Parser.java:290:in `yechtparse'
from Parser.java:284:in `parse'
from YParser.java:152:in `load'
from YParser$s$0$1$load.gen:65535:in `call'
from JavaMethod.java:630:in `call'
from DynamicMethod.java:205:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from CallOneArgNode.java:57:in `interpret'
from LocalAsgnNode.java:123:in `interpret'
from NewlineNode.java:103:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:190:in `call'
from DefaultMethod.java:179:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from CallOneArgNode.java:57:in `interpret'
from LocalAsgnNode.java:123:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:190:in `call'
from DefaultMethod.java:179:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from CallOneArgNode.java:57:in `interpret'
from NewlineNode.java:103:in `interpret'
from RescueNode.java:216:in `executeBody'
from RescueNode.java:120:in `interpretWithJavaExceptions'
from RescueNode.java:110:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:190:in `call'
from DefaultMethod.java:179:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from FCallOneArgNode.java:36:in `interpret'
from InstAsgnNode.java:95:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from EnsureNode.java:96:in `interpret'
from BeginNode.java:83:in `interpret'
from NewlineNode.java:103:in `interpret'
from WhenOneArgNode.java:36:in `whenSlowTest'
from WhenOneArgNode.java:46:in `when'
from CaseNode.java:133:in `interpret'
from NewlineNode.java:103:in `interpret'
from ASTInterpreter.java:111:in `INTERPRET_BLOCK'
from InterpretedBlock.java:374:in `evalBlockBody'
from InterpretedBlock.java:347:in `yield'
from InterpretedBlock.java:304:in `yield'
from Block.java:130:in `yield'
from YieldNode.java:112:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:111:in `INTERPRET_BLOCK'
from InterpretedBlock.java:374:in `evalBlockBody'
from InterpretedBlock.java:295:in `yield'
from InterpretedBlock.java:229:in `yieldSpecific'
from Block.java:99:in `yieldSpecific'
from RubyKernel.java:1418:in `loop'
from RubyKernel$s$0$0$loop.gen:65535:in `call'
from CachingCallSite.java:272:in `cacheAndCall'
from CachingCallSite.java:114:in `callBlock'
from CachingCallSite.java:123:in `callIter'
from FCallNoArgBlockNode.java:32:in `interpret'
from NewlineNode.java:103:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:169:in `call'
from DefaultMethod.java:171:in `call'
from CachingCallSite.java:272:in `cacheAndCall'
from CachingCallSite.java:114:in `callBlock'
from CachingCallSite.java:123:in `callIter'
from CallNoArgBlockNode.java:64:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:255:in `call'
from DefaultMethod.java:203:in `call'
from CachingCallSite.java:312:in `cacheAndCall'
from CachingCallSite.java:182:in `callBlock'
from CachingCallSite.java:186:in `call'
from RubyClass.java:806:in `newInstance'
from RubyClass$i$newInstance.gen:65535:in `call'
from JavaMethod.java:283:in `call'
from WrapperMethod.java:62:in `call'
from CachingCallSite.java:302:in `cacheAndCall'
from CachingCallSite.java:173:in `call'
from FCallTwoArgNode.java:38:in `interpret'
from LocalAsgnNode.java:123:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from EnsureNode.java:96:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:255:in `call'
from DefaultMethod.java:203:in `call'
from CachingCallSite.java:312:in `cacheAndCall'
from CachingCallSite.java:182:in `callBlock'
from CachingCallSite.java:186:in `call'
from CallTwoArgBlockPassNode.java:62:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:298:in `call'
from DefaultMethod.java:219:in `call'
from CachingCallSite.java:332:in `cacheAndCall'
from CachingCallSite.java:216:in `callBlock'
from CachingCallSite.java:225:in `callIter'
from CallThreeArgBlockNode.java:64:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:276:in `call'
from DefaultMethod.java:211:in `call'
from CachingCallSite.java:322:in `cacheAndCall'
from CachingCallSite.java:207:in `call'
from FCallThreeArgNode.java:40:in `interpret'
from NewlineNode.java:103:in `interpret'
from ASTInterpreter.java:111:in `INTERPRET_BLOCK'
from InterpretedBlock.java:374:in `evalBlockBody'
from InterpretedBlock.java:347:in `yield'
from InterpretedBlock.java:304:in `yield'
from Block.java:130:in `yield'
from RubyIO.java:1121:in `open'
from RubyKernel.java:298:in `open'
from RubyKernel$s$0$2$open.gen:65535:in `call'
from DynamicMethod.java:217:in `call'
from CachingCallSite.java:312:in `cacheAndCall'
from CachingCallSite.java:182:in `callBlock'
from CachingCallSite.java:191:in `callIter'
from FCallTwoArgBlockNode.java:34:in `interpret'
from NewlineNode.java:103:in `interpret'
from RescueNode.java:216:in `executeBody'
from RescueNode.java:120:in `interpretWithJavaExceptions'
from RescueNode.java:110:in `interpret'
from BeginNode.java:83:in `interpret'
from NewlineNode.java:103:in `interpret'
from IfNode.java:119:in `interpret'
from IfNode.java:119:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:233:in `call'
from DefaultMethod.java:195:in `call'
from CachingCallSite.java:302:in `cacheAndCall'
from CachingCallSite.java:173:in `call'
from CallTwoArgNode.java:59:in `interpret'
from InstAsgnNode.java:95:in `interpret'
from NewlineNode.java:103:in `interpret'
from RescueNode.java:216:in `executeBody'
from RescueNode.java:120:in `interpretWithJavaExceptions'
from RescueNode.java:110:in `interpret'
from BeginNode.java:83:in `interpret'
from NewlineNode.java:103:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:147:in `call'
from DefaultMethod.java:163:in `call'
from CachingCallSite.java:262:in `cacheAndCall'
from CachingCallSite.java:105:in `call'
from VCallNode.java:85:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:255:in `call'
from DefaultMethod.java:203:in `call'
from CachingCallSite.java:312:in `cacheAndCall'
from CachingCallSite.java:182:in `callBlock'
from CachingCallSite.java:186:in `call'
from RubyClass.java:806:in `newInstance'
from RubyClass$i$newInstance.gen:65535:in `call'
from JavaMethod.java:283:in `call'
from CachingCallSite.java:302:in `cacheAndCall'
from CachingCallSite.java:173:in `call'
from CallTwoArgNode.java:59:in `interpret'
from DAsgnNode.java:110:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:111:in `INTERPRET_BLOCK'
from InterpretedBlock.java:374:in `evalBlockBody'
from InterpretedBlock.java:347:in `yield'
from InterpretedBlock.java:304:in `yield'
from Block.java:130:in `yield'
from RubyArray.java:1595:in `eachCommon'
from RubyArray.java:1602:in `each'
from RubyArray$i$0$0$each.gen:65535:in `call'
from CachingCallSite.java:272:in `cacheAndCall'
from CachingCallSite.java:114:in `callBlock'
from CachingCallSite.java:123:in `callIter'
from CallNoArgBlockNode.java:64:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:233:in `call'
from DefaultMethod.java:195:in `call'
from CachingCallSite.java:302:in `cacheAndCall'
from CachingCallSite.java:173:in `call'
from CallTwoArgNode.java:59:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from RescueNode.java:216:in `executeBody'
from RescueNode.java:120:in `interpretWithJavaExceptions'
from RescueNode.java:110:in `interpret'
from BeginNode.java:83:in `interpret'
from NewlineNode.java:103:in `interpret'
from ASTInterpreter.java:111:in `INTERPRET_BLOCK'
from InterpretedBlock.java:374:in `evalBlockBody'
from InterpretedBlock.java:347:in `yield'
from InterpretedBlock.java:304:in `yield'
from Block.java:130:in `yield'
from RubyArray.java:1595:in `eachCommon'
from RubyArray.java:1602:in `each'
from RubyArray$i$0$0$each.gen:65535:in `call'
from CachingCallSite.java:272:in `cacheAndCall'
from CachingCallSite.java:114:in `callBlock'
from CachingCallSite.java:123:in `callIter'
from CallNoArgBlockNode.java:64:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:147:in `call'
from DefaultMethod.java:163:in `call'
from CachingCallSite.java:262:in `cacheAndCall'
from CachingCallSite.java:105:in `call'
from VCallNode.java:85:in `interpret'
from NewlineNode.java:103:in `interpret'
from IfNode.java:119:in `interpret'
from IfNode.java:119:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:276:in `call'
from DefaultMethod.java:211:in `call'
from CachingCallSite.java:322:in `cacheAndCall'
from CachingCallSite.java:207:in `call'
from CallSpecialArgNode.java:71:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from CaseNode.java:138:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:190:in `call'
from DefaultMethod.java:179:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from FCallOneArgNode.java:36:in `interpret'
from NewlineNode.java:103:in `interpret'
from RescueNode.java:216:in `executeBody'
from RescueNode.java:120:in `interpretWithJavaExceptions'
from RescueNode.java:110:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:190:in `call'
from DefaultMethod.java:179:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from CallOneArgNode.java:57:in `interpret'
from NewlineNode.java:103:in `interpret'
from BlockNode.java:71:in `interpret'
from ASTInterpreter.java:74:in `INTERPRET_METHOD'
from InterpretedMethod.java:190:in `call'
from DefaultMethod.java:179:in `call'
from CachingCallSite.java:282:in `cacheAndCall'
from CachingCallSite.java:139:in `call'
from D:\tools\jruby-1.6.1\bin\gem:21:in `chained_0_rescue_1$RUBY$SYNTHETIC__file__'
from D:\tools\jruby-1.6.1\bin\gem:20:in `__file__'
from D:\tools\jruby-1.6.1\bin\gem:-1:in `load'
from Ruby.java:671:in `runScript'
from Ruby.java:575:in `runNormally'
from Ruby.java:424:in `runFromMain'
from Main.java:278:in `doRunFromMain'
from Main.java:198:in `internalRun'
from Main.java:164:in `run'
from Main.java:148:in `run'
from Main.java:128:in `main'
Redacting, I'm behind on uglifier versions.
I'm using multi_json via Tilt. My use of Tilt has been successful until I added JrJackson as a dependency in my Gemfile. I note that JrJackson is not listed as one of multi_json's supported engines, but nonetheless it appears as though it's getting loaded and the following error occurs inside multi_json as a result of calling render
on a Tilt template:
uninitialized constant JrJackson::Json::ParserError
org/jruby/RubyModule.java:2642:in `const_missing'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/rake-0.9.2.2/lib/rake/ext/module.rb:36:in `const_missing'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json/engines/json_gem.rb:8:in `JsonGem'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json/engines/json_gem.rb:7:in `Engines'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json/engines/json_gem.rb:5:in `MultiJson'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json/engines/json_gem.rb:4:in `(root)'
org/jruby/RubyKernel.java:1033:in `require'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json/engines/json_gem.rb:62:in `engine='
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json.rb:18:in `engine'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/multi_json-1.1.0/lib/multi_json.rb:86:in `encode'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/execjs-1.3.0/lib/execjs/external_runtime.rb:32:in `call'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/coffee-script-2.2.0/lib/coffee_script.rb:57:in `compile'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/tilt-1.3.3/lib/tilt/coffee.rb:46:in `evaluate'
/Users/semperos/.rbenv/versions/jruby-1.6.7/lib/ruby/gems/1.8/gems/tilt-1.3.3/lib/tilt/template.rb:76:in `render'
Is there a way to make multi_json not use JrJackson? Why is it being automatically loaded if its not supported?
I see this commit:
renames MultiJson.default_engine to MultiJson.default_adapter. This breaks the TweetStream gem (and possibly others?). Should TweetStream be fixed, or MultiJson?
Currently, the error message raised when trying to decode
when no engine is available is
Did not recognize your engine specification.
Please specify either a symbol or a class.
That's because MultiJson. default_engine
will return nil
, which is then used by MultiJson.engine
as follows:
self.engine = self.default_engine # self.engine = nil
nil
is not allowed as a parameter to MultiJson.engine=
. I believe the right solution is to raise in default_engine
something akin to "Could not find a JSON engine. Do you have one installed?"
Hi Guys,
I have updated to v 1.6.1 and tests in my app failed.
Short explanation - method .load(.., options) removes key from options.
I have created 2 branches and added same test to both:
from v1.6.1 https://github.com/mshytikov/multi_json/tree/release-1.6.1
and
from current master https://github.com/mshytikov/multi_json/tree/current-master
As you can see tests in v1.6.1 - fails, but master is ok.
Could you please release a new version from master.
Thank you.
https://github.com/intridea/multi_json/blob/master/lib/multi_json/adapters/oj.rb
This overwrites the Oj default options and doesn't allow custom options to be set.
I believe the fix is to change the set of engines MultiJson#default_engine
searches from
%w(yajl json active_support json/pure)
to
%w(yajl json_gem active_support json/pure)
Alternatively, rename lib/multi_json/engines/json_gem.rb
to lib/multi_json/engines/json.rb
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.