From 24a0659f95ccde38c62de565af1363f47d9575e7 Mon Sep 17 00:00:00 2001 From: Luka Dornhecker Date: Tue, 8 Mar 2022 19:38:52 +0100 Subject: [PATCH] [Ruby] allow encode json options to be an object that responds to to_hash (#9513) * allow encode json options to be an object that responds to to_hash fixes #9500 * try to convert options arg to hash if it is not a hash --- ruby/ext/google/protobuf_c/message.c | 6 +++++- .../java/com/google/protobuf/jruby/RubyMessage.java | 10 +++++++++- ruby/tests/common_tests.rb | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index b889230843..5d1e72e2ec 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -1141,7 +1141,11 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { if (argc == 2) { VALUE hash_args = argv[1]; if (TYPE(hash_args) != T_HASH) { - rb_raise(rb_eArgError, "Expected hash arguments."); + if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, rb_str_new2("to_h")))) { + hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0); + } else { + rb_raise(rb_eArgError, "Expected hash arguments."); + } } if (RTEST(rb_hash_lookup2(hash_args, diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java index b0a1f9010b..f55eb9b285 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -555,7 +555,15 @@ public class RubyMessage extends RubyObject { String result; if (args.length > 1) { - RubyHash options = (RubyHash) args[1]; + RubyHash options; + if (args[1] instanceof RubyHash) { + options = (RubyHash) args[1]; + } else if (args[1].respondsTo("to_h")) { + options = (RubyHash) args[1].callMethod(context, "to_h"); + } else { + throw runtime.newArgumentError("Expected hash arguments."); + } + IRubyObject emitDefaults = options.fastARef(runtime.newSymbol("emit_defaults")); IRubyObject preserveNames = options.fastARef(runtime.newSymbol("preserve_proto_fieldnames")); diff --git a/ruby/tests/common_tests.rb b/ruby/tests/common_tests.rb index cd48b6916f..358846916d 100644 --- a/ruby/tests/common_tests.rb +++ b/ruby/tests/common_tests.rb @@ -870,6 +870,9 @@ module CommonTests decoded_msg = Google::Protobuf.decode_json(proto_module::TestMessage, encoded_msg) assert_equal proto_module::TestMessage.decode_json(m.to_json), decoded_msg + + assert_equal [m].to_json, Google::Protobuf.encode_json([m]) + assert_equal proto_module::TestMessage.decode_json([m.to_json].first), decoded_msg end def test_def_errors