[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
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index b889230..5d1e72e 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -1141,7 +1141,11 @@
   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 b0a1f90..f55eb9b 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 @@
         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 cd48b69..3588469 100644
--- a/ruby/tests/common_tests.rb
+++ b/ruby/tests/common_tests.rb
@@ -870,6 +870,9 @@
 
     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