From 97a73ef076f39a4edba08853b57995ffe1adcf2c Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 5 Nov 2024 12:59:58 +0100 Subject: [PATCH] Raise JSON::GeneratorError instead of Encoding::UndefinedConversionError Followup: https://github.com/ruby/json/pull/633 That's what was raised historically. You could argue that this new exception is more precise, but I've encountered some real production code that expected the old behavior and that was broken by this change. --- ext/json/ext/generator/generator.c | 4 ++++ java/src/json/ext/Generator.java | 20 +++++++++++++------- java/src/json/ext/GeneratorMethods.java | 2 +- lib/json/common.rb | 2 ++ lib/json/pure/generator.rb | 2 ++ test/json/json_generator_test.rb | 14 +++++++++++--- 6 files changed, 33 insertions(+), 11 deletions(-) diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 645500d04..80539af6c 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -1036,6 +1036,10 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc) struct generate_json_data *data = (struct generate_json_data *)d; fbuffer_free(data->buffer); + if (RBASIC_CLASS(exc) == rb_path2class("Encoding::UndefinedConversionError")) { + exc = rb_exc_new_str(eGeneratorError, rb_funcall(exc, rb_intern("message"), 0)); + } + rb_exc_raise(exc); return Qundef; diff --git a/java/src/json/ext/Generator.java b/java/src/json/ext/Generator.java index b149feb36..f76dcb383 100644 --- a/java/src/json/ext/Generator.java +++ b/java/src/json/ext/Generator.java @@ -17,6 +17,7 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; +import org.jruby.exceptions.RaiseException; public final class Generator { private Generator() { @@ -402,14 +403,19 @@ void generate(Session session, RubyString object, ByteList buffer) { RuntimeInfo info = session.getInfo(); RubyString src; - if (object.encoding(session.getContext()) != info.utf8.get()) { - src = (RubyString)object.encode(session.getContext(), - info.utf8.get()); - } else { - src = object; - } + try { + if (object.encoding(session.getContext()) != info.utf8.get()) { + src = (RubyString)object.encode(session.getContext(), + info.utf8.get()); + } else { + src = object; + } - session.getStringEncoder().encode(src.getByteList(), buffer); + session.getStringEncoder().encode(src.getByteList(), buffer); + } catch (RaiseException re) { + throw Utils.newException(session.getContext(), Utils.M_GENERATOR_ERROR, + re.getMessage()); + } } }; diff --git a/java/src/json/ext/GeneratorMethods.java b/java/src/json/ext/GeneratorMethods.java index bde7a18d9..b6ffdf9cf 100644 --- a/java/src/json/ext/GeneratorMethods.java +++ b/java/src/json/ext/GeneratorMethods.java @@ -103,7 +103,7 @@ public static class RbString { public static IRubyObject to_json(ThreadContext context, IRubyObject vSelf, IRubyObject[] args) { return Generator.generateJson(context, (RubyString)vSelf, - Generator.STRING_HANDLER, args); + Generator.STRING_HANDLER, args); } /** diff --git a/lib/json/common.rb b/lib/json/common.rb index 84f2a57c8..e679637c4 100644 --- a/lib/json/common.rb +++ b/lib/json/common.rb @@ -293,6 +293,8 @@ def generate(obj, opts = nil) else State.generate(obj, opts) end + rescue Encoding::UndefinedConversionError => error + raise ::JSON::GeneratorError, error.message end # :stopdoc: diff --git a/lib/json/pure/generator.rb b/lib/json/pure/generator.rb index 21e765467..05ffb6314 100644 --- a/lib/json/pure/generator.rb +++ b/lib/json/pure/generator.rb @@ -557,6 +557,8 @@ def to_json(state = nil, *args) else %("#{JSON.utf8_to_json(string, state.script_safe)}") end + rescue Encoding::UndefinedConversionError => error + raise ::JSON::GeneratorError, error.message end # Module that holds the extending methods if, the String module is diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb index 112c03b22..3bc7eb80a 100755 --- a/test/json/json_generator_test.rb +++ b/test/json/json_generator_test.rb @@ -477,12 +477,20 @@ def test_invalid_encoding_string end assert_includes error.message, "source sequence is illegal/malformed utf-8" - assert_raise(Encoding::UndefinedConversionError) do + assert_raise(JSON::GeneratorError) do + JSON.dump("\x82\xAC\xEF".b) + end + + assert_raise(JSON::GeneratorError) do "\x82\xAC\xEF".b.to_json end - assert_raise(Encoding::UndefinedConversionError) do - JSON.dump("\x82\xAC\xEF".b) + assert_raise(JSON::GeneratorError) do + ["\x82\xAC\xEF".b].to_json + end + + assert_raise(JSON::GeneratorError) do + { foo: "\x82\xAC\xEF".b }.to_json end end