private static void addDefaultsAndExtensions(
     Map<String, Set<Descriptors.FieldDescriptor>> e,
     Map<String, Object> defaultValueMap,
     Descriptors.Descriptor d) {
   for (Descriptors.FieldDescriptor fieldDescriptor : d.getExtensions()) {
     String containingType = fieldDescriptor.getContainingType().getFullName();
     Set<Descriptors.FieldDescriptor> fieldDescriptors = e.get(containingType);
     if (fieldDescriptors == null) {
       fieldDescriptors = new LinkedHashSet<>();
       e.put(containingType, fieldDescriptors);
     }
     fieldDescriptors.add(fieldDescriptor);
     if (fieldDescriptor.hasDefaultValue()) {
       defaultValueMap.put(
           fieldDescriptor.getContainingType().getFullName() + "." + fieldDescriptor.getName(),
           fieldDescriptor.getDefaultValue());
     }
   }
   for (Descriptors.FieldDescriptor fieldDescriptor : d.getFields()) {
     if (fieldDescriptor.hasDefaultValue()) {
       defaultValueMap.put(
           d.getFullName() + "." + fieldDescriptor.getName(), fieldDescriptor.getDefaultValue());
     }
   }
   for (Descriptors.Descriptor nestedType : d.getNestedTypes()) {
     addDefaultsAndExtensions(e, defaultValueMap, nestedType);
   }
 }
 /**
  * Populates a map of protobuf extensions and map with the default values for each message field
  * from a map of file descriptors.
  *
  * @param fileDescriptorMap Map of file descriptors
  * @param typeToExtensionMap Map of extensions to populate
  * @param defaultValueMap Map of default values to populate
  */
 public static void populateDefaultsAndExtensions(
     Map<String, Descriptors.FileDescriptor> fileDescriptorMap,
     Map<String, Set<Descriptors.FieldDescriptor>> typeToExtensionMap,
     Map<String, Object> defaultValueMap) {
   for (Descriptors.FileDescriptor f : fileDescriptorMap.values()) {
     // go over every file descriptor and look for extensions and default values of those
     // extensions
     for (Descriptors.FieldDescriptor fieldDescriptor : f.getExtensions()) {
       String containingType = fieldDescriptor.getContainingType().getFullName();
       Set<Descriptors.FieldDescriptor> fieldDescriptors = typeToExtensionMap.get(containingType);
       if (fieldDescriptors == null) {
         fieldDescriptors = new LinkedHashSet<>();
         typeToExtensionMap.put(containingType, fieldDescriptors);
       }
       fieldDescriptors.add(fieldDescriptor);
       if (fieldDescriptor.hasDefaultValue()) {
         defaultValueMap.put(
             containingType + "." + fieldDescriptor.getName(), fieldDescriptor.getDefaultValue());
       }
     }
     // go over messages within file descriptor and look for all fields and extensions and their
     // defaults
     for (Descriptors.Descriptor d : f.getMessageTypes()) {
       addDefaultsAndExtensions(typeToExtensionMap, defaultValueMap, d);
     }
   }
 }
  /**
   * Creates an SDC Record Field from the provided protobuf message and descriptor.
   *
   * @param record record to be augmented
   * @param fieldPath field path in the record to insert new Field
   * @param fieldDescriptor descriptor for this message
   * @param messageTypeToExtensionMap protobuf type extensions
   * @param message protobuf message to decode
   * @return reference to the Field added to the record.
   * @throws DataParserException
   */
  @SuppressWarnings("unchecked")
  private static Field createField(
      Record record,
      String fieldPath,
      Descriptors.FieldDescriptor fieldDescriptor,
      Map<String, Set<Descriptors.FieldDescriptor>> messageTypeToExtensionMap,
      Object message)
      throws DataParserException {
    Field newField;
    if (message == null) {
      // If the message does not contain required fields then builder.build() throws
      // UninitializedMessageException
      Object defaultValue = null;
      // get default values only for optional fields and non-message types
      if (fieldDescriptor.isOptional()
          && fieldDescriptor.getJavaType() != Descriptors.FieldDescriptor.JavaType.MESSAGE) {
        defaultValue = fieldDescriptor.getDefaultValue();
      }
      newField = Field.create(getFieldType(fieldDescriptor.getJavaType()), defaultValue);
    } else if (fieldDescriptor.isMapField()) {
      // Map entry (protobuf 3 map)
      Map<String, Field> sdcMapFieldValues = new HashMap<>();
      Collection<DynamicMessage> mapEntries = (Collection<DynamicMessage>) message;
      // MapEntry
      for (DynamicMessage dynamicMessage : mapEntries) {
        // MapEntry has 2 fields, key and value
        Map<Descriptors.FieldDescriptor, Object> kv = dynamicMessage.getAllFields();
        String key = null;
        Object value = null;
        Descriptors.FieldDescriptor valueDescriptor = null;
        for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : kv.entrySet()) {
          switch (entry.getKey().getName()) {
            case KEY:
              key = entry.getValue().toString();
              break;
            case VALUE:
              value = entry.getValue();
              valueDescriptor = entry.getKey();
              break;
            default:
              throw new DataParserException(Errors.PROTOBUF_09, entry.getKey().getName());
          }
        }
        if (key != null && valueDescriptor != null) {
          sdcMapFieldValues.put(
              key,
              createSdcField(record, fieldPath, valueDescriptor, messageTypeToExtensionMap, value));
        }
      }

      newField = Field.create(sdcMapFieldValues);
    } else if (fieldDescriptor.isRepeated()) {
      // List entry (repeated)
      List<?> list = (List<?>) message;
      List<Field> listField = new ArrayList<>();
      for (int i = 0; i < list.size(); i++) {
        if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
          listField.add(
              protobufToSdcField(
                  record,
                  fieldPath + "[" + i + "]",
                  fieldDescriptor.getMessageType(),
                  messageTypeToExtensionMap,
                  list.get(i)));
        } else {
          listField.add(
              createSdcField(
                  record,
                  fieldPath + "[" + i + "]",
                  fieldDescriptor,
                  messageTypeToExtensionMap,
                  list.get(i)));
        }
      }
      newField = Field.create(listField);
    } else {
      // normal entry
      newField =
          createSdcField(record, fieldPath, fieldDescriptor, messageTypeToExtensionMap, message);
    }
    return newField;
  }