Skip to content

Commit

Permalink
Raise JSON::GeneratorError instead of Encoding::UndefinedConversionError
Browse files Browse the repository at this point in the history
Followup: #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.
  • Loading branch information
byroot committed Nov 5, 2024
1 parent dcd8292 commit 1c44851
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 11 deletions.
4 changes: 4 additions & 0 deletions ext/json/ext/generator/generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 13 additions & 7 deletions java/src/json/ext/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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());
}
}
};

Expand Down
10 changes: 9 additions & 1 deletion lib/json/pure/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,13 @@ def generate(obj)
# Assumes !@ascii_only, !@script_safe
private def fast_serialize_string(string, buf) # :nodoc:
buf << '"'
string = string.encode(::Encoding::UTF_8) unless string.encoding == ::Encoding::UTF_8
unless string.encoding == ::Encoding::UTF_8
begin
string = string.encode(::Encoding::UTF_8)
rescue Encoding::UndefinedConversionError => error
raise GeneratorError, error.message
end
end
raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?

if /["\\\x0-\x1f]/n.match?(string)
Expand Down Expand Up @@ -557,6 +563,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
Expand Down
14 changes: 11 additions & 3 deletions test/json/json_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 1c44851

Please sign in to comment.