Skip to content

[Ruby] Message hashes including non-oneof values #6167

Closed
@blowmage

Description

What language does this apply to?

Ruby

Describe the problem you are trying to solve.

The Ruby Hash a Message object creates sometimes includes values for fields that are not applicable, specifically fields that are not set as part of the oneof.

Describe the solution you'd like

The Ruby Hash a Message object creates does not include any field that is set to the default value.

Describe alternatives you've considered

The Ruby Hash a Message object creates excludes values for oneof fields that are not set.

Additional context

The Ruby Hash produced by Message#to_h sometimes contain fields of a oneof that are not currently set, or were reset to their default value. Currently, if a oneof value is changed from one field to another, the previous field (with it's default value) will be in the hash along with the new field (and the set value). This makes it difficult to recreate the Message object from the hash. Ideally, the Message should be able to round-trip to/from a Ruby Hash just as it can round-trip to/from a binary proto stream and to/from JSON.

The ruby/tests/basic_proto2.rb file has the following test:

def test_to_h
  m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
  expected_result = {
    :optional_bool=>true,
    :optional_double=>-10.100001,
    :optional_string=>"foo",
    :repeated_string=>["bar1", "bar2"],
  }
  assert_equal expected_result, m.to_h

  m = OneofMessage.new(:a => "foo")
  expected_result = {:a => "foo"}
  assert_equal expected_result, m.to_h
end

This test can be updated with the following code to demonstrate the problematic behavior:

# oneof is not set
m = OneofMessage.new
assert_equal "", m.a
assert_equal 0, m.b
assert_nil m.my_oneof
expected_result = {}
assert_equal expected_result, m.to_h

# oneof is updated to a
m.a = "foo"
assert_equal "foo", m.a
assert_equal 0, m.b
assert_equal :a, m.my_oneof
expected_result = {:a => "foo"}
assert_equal expected_result, m.to_h

# oneof is updated to b
m.b = 42
assert_equal "", m.a
assert_equal 42, m.b
assert_equal :b, m.my_oneof
expected_result = {:b => 42}
assert_equal expected_result, m.to_h # actual is {:a=>"", :b=>42}

# create new message object, using incorrect hash
m = OneofMessage.new({:a=>"foo", :b=>0})
assert_equal :a, m.my_oneof # actual is :b
expected_result = {:a => "foo"}
assert_equal expected_result, m.to_h # actual is {:a=>"foo", :b=>0}

Additionally, I think it might be a good idea if the Ruby Hash objects simply omitted any field that was set to it's default value. I believe that would correct this issue and the Ruby Hash would be more concise.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions