From 8aa2b177f156393ce607b4ffea8c1ac28560c746 Mon Sep 17 00:00:00 2001 From: Minh Quy Date: Tue, 7 Mar 2023 11:20:19 -0800 Subject: [PATCH] feat(6178): emit ruby enum as integer (#11673) Fixes #6178 - Add a new option `enums_as_integers` to emit enum as integer value. Closes #11673 COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/11673 from MQuy:feat/6178-ruby-enum-as-integer 90f986a5fd2f5e8bda3f338c67304ef96feee446 PiperOrigin-RevId: 514789180 --- ruby/ext/google/protobuf_c/message.c | 6 ++++ .../google/protobuf/jruby/RubyMessage.java | 7 +++++ ruby/tests/encode_decode_test.rb | 28 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 067a446615..ab19d2762f 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -1164,6 +1164,12 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { Qfalse))) { options |= upb_JsonEncode_EmitDefaults; } + + if (RTEST(rb_hash_lookup2(hash_args, + ID2SYM(rb_intern("format_enums_as_integers")), + Qfalse))) { + options |= upb_JsonEncode_FormatEnumsAsIntegers; + } } upb_Status_Clear(&status); 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 92a31d6df2..dc76e2d4c0 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -669,6 +669,7 @@ public class RubyMessage extends RubyObject { * @param options [Hash] options for the decoder * preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase) * emit_defaults: set true to emit 0/false values (default is to omit them) + * format_enums_as_integers: set true to emit enum values as integer (default is string) */ @JRubyMethod(name = "encode_json", required = 1, optional = 1, meta = true) public static IRubyObject encodeJson( @@ -690,6 +691,8 @@ public class RubyMessage extends RubyObject { IRubyObject emitDefaults = options.fastARef(runtime.newSymbol("emit_defaults")); IRubyObject preserveNames = options.fastARef(runtime.newSymbol("preserve_proto_fieldnames")); + IRubyObject printingEnumsAsInts = + options.fastARef(runtime.newSymbol("format_enums_as_integers")); if (emitDefaults != null && emitDefaults.isTrue()) { printer = printer.includingDefaultValueFields(); @@ -698,6 +701,10 @@ public class RubyMessage extends RubyObject { if (preserveNames != null && preserveNames.isTrue()) { printer = printer.preservingProtoFieldNames(); } + + if (printingEnumsAsInts != null && printingEnumsAsInts.isTrue()) { + printer = printer.printingEnumsAsInts(); + } } printer = printer.usingTypeRegistry( diff --git a/ruby/tests/encode_decode_test.rb b/ruby/tests/encode_decode_test.rb index df2cd3632d..710e754990 100755 --- a/ruby/tests/encode_decode_test.rb +++ b/ruby/tests/encode_decode_test.rb @@ -84,6 +84,34 @@ class EncodeDecodeTest < Test::Unit::TestCase ) assert_match 'optional_int32', json + + + # Test for enums printing as ints. + msg = A::B::C::TestMessage.new({ optional_enum: 1 }) + json = A::B::C::TestMessage.encode_json( + msg, + { :format_enums_as_integers => true } + ) + + assert_match '"optionalEnum":1', json + + # Test for default enum being printed as int. + msg = A::B::C::TestMessage.new({ optional_enum: 0 }) + json = A::B::C::TestMessage.encode_json( + msg, + { :format_enums_as_integers => true, :emit_defaults => true } + ) + + assert_match '"optionalEnum":0', json + + # Test for repeated enums printing as ints. + msg = A::B::C::TestMessage.new({ repeated_enum: [0,1,2,3] }) + json = A::B::C::TestMessage.encode_json( + msg, + { :format_enums_as_integers => true } + ) + + assert_match '"repeatedEnum":[0,1,2,3]', json end def test_encode_wrong_msg