From 87714836e328ca3f98c93a451be26bfd35e804b7 Mon Sep 17 00:00:00 2001 From: Zachary Anker Date: Tue, 12 Sep 2017 12:52:15 -0700 Subject: Allow initializing a chain of protos using only a hash --- .../com/google/protobuf/jruby/RubyMessage.java | 43 ++++++++++++++-------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'ruby/src') 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 733ccfbc..59040394 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -82,8 +82,8 @@ public class RubyMessage extends RubyObject { hash.visitAll(new RubyHash.Visitor() { @Override public void visit(IRubyObject key, IRubyObject value) { - if (!(key instanceof RubySymbol)) - throw runtime.newTypeError("Expected symbols as hash keys in initialization map."); + if (!(key instanceof RubySymbol) && !(key instanceof RubyString)) + throw runtime.newTypeError("Expected string or symbols as hash keys in initialization map."); final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key); if (Utils.isMapEntry(fieldDescriptor)) { @@ -103,9 +103,15 @@ public class RubyMessage extends RubyObject { if (oneof != null) { oneofCases.put(oneof, fieldDescriptor); } + + if (value instanceof RubyHash && fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { + RubyDescriptor descriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + RubyClass typeClass = (RubyClass) descriptor.msgclass(context); + value = (IRubyObject) typeClass.newInstance(context, value, Block.NULL_BLOCK); + } + fields.put(fieldDescriptor, value); } - } }); } @@ -518,19 +524,12 @@ public class RubyMessage extends RubyObject { val = value.isTrue(); break; case BYTES: + Utils.validateStringEncoding(context, fieldDescriptor.getType(), value); + val = ByteString.copyFrom(((RubyString) value).getBytes()); + break; case STRING: Utils.validateStringEncoding(context, fieldDescriptor.getType(), value); - RubyString str = (RubyString) value; - switch (fieldDescriptor.getType()) { - case BYTES: - val = ByteString.copyFrom(str.getBytes()); - break; - case STRING: - val = str.asJavaString(); - break; - default: - break; - } + val = ((RubyString) value).asJavaString(); break; case MESSAGE: RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); @@ -543,7 +542,7 @@ public class RubyMessage extends RubyObject { if (Utils.isRubyNum(value)) { val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); - } else if (value instanceof RubySymbol) { + } else if (value instanceof RubySymbol || value instanceof RubyString) { val = enumDescriptor.findValueByName(value.asJavaString()); } else { throw runtime.newTypeError("Expected number or symbol type for enum field."); @@ -741,8 +740,20 @@ public class RubyMessage extends RubyObject { Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) { RubyArray arr = value.convertToArray(); RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor); + + RubyClass typeClass = null; + if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { + RubyDescriptor descriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + typeClass = (RubyClass) descriptor.msgclass(context); + } + for (int i = 0; i < arr.size(); i++) { - repeatedField.push(context, arr.eltInternal(i)); + IRubyObject row = arr.eltInternal(i); + if (row instanceof RubyHash && typeClass != null) { + row = (IRubyObject) typeClass.newInstance(context, row, Block.NULL_BLOCK); + } + + repeatedField.push(context, row); } return repeatedField; } -- cgit v1.2.3