Example #1
0
  @Test
  public void structuredAndUnstructuredOptions() throws Exception {
    // From https://developers.google.com/protocol-buffers/docs/proto#options
    Schema schema =
        new SchemaBuilder()
            .add(
                "foo.proto",
                ""
                    + "import \"google/protobuf/descriptor.proto\";\n"
                    + "message FooOptions {\n"
                    + "  optional int32 opt1 = 1;\n"
                    + "  optional string opt2 = 2;\n"
                    + "}\n"
                    + "\n"
                    + "extend google.protobuf.FieldOptions {\n"
                    + "  optional FooOptions foo_options = 1234;\n"
                    + "}\n"
                    + "\n"
                    + "message Bar {\n"
                    + "  optional int32 a = 1 [(foo_options).opt1 = 123, (foo_options).opt2 = \"baz\"];\n"
                    + "  optional int32 b = 2 [(foo_options) = { opt1: 456 opt2: \"quux\" }];\n"
                    + "}\n")
            .add("google/protobuf/descriptor.proto")
            .build();

    ProtoMember fooOptions = ProtoMember.get(Options.FIELD_OPTIONS, "foo_options");
    ProtoMember opt1 = ProtoMember.get(ProtoType.get("FooOptions"), "opt1");
    ProtoMember opt2 = ProtoMember.get(ProtoType.get("FooOptions"), "opt2");

    MessageType bar = (MessageType) schema.getType("Bar");
    assertThat(bar.field("a").options().map())
        .isEqualTo(ImmutableMap.of(fooOptions, ImmutableMap.of(opt1, "123", opt2, "baz")));
    assertThat(bar.field("b").options().map())
        .isEqualTo(ImmutableMap.of(fooOptions, ImmutableMap.of(opt1, "456", opt2, "quux")));
  }
Example #2
0
 private void gatherFields(Multimap<ProtoType, ProtoMember> sink, ProtoType type, Object o) {
   if (o instanceof Map) {
     for (Map.Entry<?, ?> entry : ((Map<?, ?>) o).entrySet()) {
       ProtoMember protoMember = (ProtoMember) entry.getKey();
       sink.put(type, protoMember);
       gatherFields(sink, protoMember.type(), entry.getValue());
     }
   } else if (o instanceof List) {
     for (Object e : (List) o) {
       gatherFields(sink, type, e);
     }
   }
 }
Example #3
0
  Map<ProtoMember, Object> canonicalizeOption(
      Linker linker, ProtoType extensionType, OptionElement option) {
    Type type = linker.get(extensionType);
    if (!(type instanceof MessageType)) {
      return null; // No known extensions for the given extension type.
    }
    MessageType messageType = (MessageType) type;

    String[] path;
    Field field = messageType.field(option.name());
    if (field != null) {
      // This is an option declared by descriptor.proto.
      path = new String[] {option.name()};
    } else {
      // This is an option declared by an extension.
      Map<String, Field> extensionsForType = messageType.extensionFieldsMap();

      path = resolveFieldPath(option.name(), extensionsForType.keySet());
      String packageName = linker.packageName();
      if (path == null && packageName != null) {
        // If the path couldn't be resolved, attempt again by prefixing it with the package name.
        path = resolveFieldPath(packageName + "." + option.name(), extensionsForType.keySet());
      }
      if (path == null) {
        return null; // Unable to find the root of this field path.
      }

      field = extensionsForType.get(path[0]);
    }

    Map<ProtoMember, Object> result = new LinkedHashMap<>();
    Map<ProtoMember, Object> last = result;
    ProtoType lastProtoType = messageType.type();
    for (int i = 1; i < path.length; i++) {
      Map<ProtoMember, Object> nested = new LinkedHashMap<>();
      last.put(ProtoMember.get(lastProtoType, field), nested);
      lastProtoType = field.type();
      last = nested;
      field = linker.dereference(field, path[i]);
      if (field == null) {
        return null; // Unable to dereference this path segment.
      }
    }

    last.put(
        ProtoMember.get(lastProtoType, field), canonicalizeValue(linker, field, option.value()));
    return result;
  }
Example #4
0
  private Object canonicalizeValue(Linker linker, Field context, Object value) {
    if (value instanceof OptionElement) {
      ImmutableMap.Builder<ProtoMember, Object> result = ImmutableMap.builder();
      OptionElement option = (OptionElement) value;
      Field field = linker.dereference(context, option.name());
      if (field == null) {
        linker.addError("unable to resolve option %s on %s", option.name(), context.type());
      } else {
        ProtoMember protoMember = ProtoMember.get(context.type(), field);
        result.put(protoMember, canonicalizeValue(linker, field, option.value()));
      }
      return coerceValueForField(context, result.build());
    }

    if (value instanceof Map) {
      ImmutableMap.Builder<ProtoMember, Object> result = ImmutableMap.builder();
      for (Map.Entry<?, ?> entry : ((Map<?, ?>) value).entrySet()) {
        String name = (String) entry.getKey();
        Field field = linker.dereference(context, name);
        if (field == null) {
          linker.addError("unable to resolve option %s on %s", name, context.type());
        } else {
          ProtoMember protoMember = ProtoMember.get(context.type(), field);
          result.put(protoMember, canonicalizeValue(linker, field, entry.getValue()));
        }
      }
      return coerceValueForField(context, result.build());
    }

    if (value instanceof List) {
      ImmutableList.Builder<Object> result = ImmutableList.builder();
      for (Object element : (List<?>) value) {
        result.addAll((List) canonicalizeValue(linker, context, element));
      }
      return coerceValueForField(context, result.build());
    }

    if (value instanceof String) {
      return coerceValueForField(context, value);
    }

    throw new IllegalArgumentException("Unexpected option value: " + value);
  }
Example #5
0
 @Test
 public void fullyQualifiedOptionFields() throws Exception {
   Schema schema =
       new SchemaBuilder()
           .add(
               "a/b/more_options.proto",
               ""
                   + "syntax = \"proto2\";\n"
                   + "package a.b;\n"
                   + "\n"
                   + "import \"google/protobuf/descriptor.proto\";\n"
                   + "\n"
                   + "extend google.protobuf.MessageOptions {\n"
                   + "  optional MoreOptions more_options = 17000;\n"
                   + "}\n"
                   + "\n"
                   + "message MoreOptions {\n"
                   + "  extensions 100 to 200;\n"
                   + "}\n")
           .add(
               "a/c/event_more_options.proto",
               ""
                   + "syntax = \"proto2\";\n"
                   + "package a.c;\n"
                   + "\n"
                   + "import \"a/b/more_options.proto\";\n"
                   + "\n"
                   + "extend a.b.MoreOptions {\n"
                   + "  optional EvenMoreOptions even_more_options = 100;\n"
                   + "}\n"
                   + "\n"
                   + "message EvenMoreOptions {\n"
                   + "  optional string string_option = 1;\n"
                   + "}\n")
           .add(
               "a/d/message.proto",
               ""
                   + "syntax = \"proto2\";\n"
                   + "package a.d;\n"
                   + "\n"
                   + "import \"a/b/more_options.proto\";\n"
                   + "import \"a/c/event_more_options.proto\";\n"
                   + "\n"
                   + "message Message {\n"
                   + "  option (a.b.more_options) = {\n"
                   + "    [a.c.even_more_options]: {string_option: \"foo\"}\n"
                   + "  };\n"
                   + "}\n")
           .add("google/protobuf/descriptor.proto")
           .build();
   ProtoType moreOptionsType = ProtoType.get("a.b.MoreOptions");
   ProtoType evenMoreOptionsType = ProtoType.get("a.c.EvenMoreOptions");
   ProtoMember moreOptions = ProtoMember.get(Options.MESSAGE_OPTIONS, "a.b.more_options");
   ProtoMember evenMoreOptions = ProtoMember.get(moreOptionsType, "a.c.even_more_options");
   ProtoMember stringOption = ProtoMember.get(evenMoreOptionsType, "string_option");
   MessageType message = (MessageType) schema.getType("a.d.Message");
   assertThat(message.options().map())
       .isEqualTo(
           ImmutableMap.of(
               moreOptions,
               ImmutableMap.of(evenMoreOptions, ImmutableMap.of(stringOption, "foo"))));
 }