带反射的嵌套协议缓冲区

时间:2013-12-17 05:09:57

标签: java protocol-buffers

假设我在.proto文件中有一条消息,其中包含以下内容

Message Foo {
    Message Bar {
        optional int32 a = 1;
        optional int32 b = 2;
    }
    optional Bar bar = 1;
}

在Java中,无论如何设置字段a只使用字符串“bar.a”?理想情况下,我想编写如下方法:

public Foo.Builder apply(Foo.Builder builder, String fieldPath, Object value) {
    // fieldPath == "bar.a"
    // This doesn't work
    FieldDescriptor fd = builder.getDefaultInstanceForType().findFieldByName(fieldPath);
    builder = builder.setField(fd, value);
}

但是当我这样做时,我得到一个IllegalArgumentException。

有谁知道如何以通用的方式做到这一点?

我也需要走另一条路

public Object getValue(Foo message, String fieldPath) {
    // This doesn't work
    FieldDescriptor fd = message.getDefaultInstanceForType().findFieldByName(fieldPath);
    return message.getField(fieldPath);
}

作为一个注释,如果fieldPath不包含分隔符(“。”)并引用基本消息,而不是嵌套消息,则此方法可以正常工作。

1 个答案:

答案 0 :(得分:6)

您需要将字段路径拆分为“。”并进行一系列查找,例如

Message subMessage =
    (Message)message.getField(
        message.getDescriptorForType().findFieldByName("bar"));
return subMessage.getField(
    subMessage.getDescriptorForType().findFieldByName("a"));

或者写:

FieldDescriptor desc = message.getDescriptorForType().findFieldByName("bar");
Message.Builder subBuilder = (Message.Builder)builder.getFieldBuilder(desc);
subBuilder.setField(
    subMessage.getDescriptorForType().findFieldByName("a"), value);
builder.setField(desc, subBuilder.build());

你当然可以编写一个分割字符串的库,并在一次调用中完成所有查找(并进行适当的错误检查)。