Example #1
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 #2
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);
  }