salesforce-lib/src/main/java/com/streamsets/pipeline/lib/salesforce/SobjectRecordCreator.java
private void getAllReferences(
      PartnerConnection partnerConnection,
      Map<String, ObjectMetadata> metadataMap,
      List<List<Pair<String, String>>> references,
      String[] allTypes,
      int depth
  ) throws ConnectionException {
    if (depth < 0) {
      return;
    }

    List<String> next = new ArrayList<>();

    for (int typeIndex = 0; typeIndex < allTypes.length; typeIndex += MAX_METADATA_TYPES) {
      int copyTo = Math.min(typeIndex + MAX_METADATA_TYPES, allTypes.length);
      String[] types = Arrays.copyOfRange(allTypes, typeIndex, copyTo);

      // Special case - we prepopulate the cache with the root sobject type - don't repeat
      // ourselves
      if (types.length > 1 || !metadataMap.containsKey(types[0])) {
        for (DescribeSObjectResult result : partnerConnection.describeSObjects(types)) {
          Map<String, Field> fieldMap = new LinkedHashMap<>();
          Map<String, Field> relationshipMap = new LinkedHashMap<>();
          for (Field field : result.getFields()) {
            fieldMap.put(field.getName().toLowerCase(), field);
            String relationshipName = field.getRelationshipName();
            if (relationshipName != null) {
              relationshipMap.put(relationshipName.toLowerCase(), field);
            }
          }
          Map<String, String> childRelationships = new LinkedHashMap<>();
          for (ChildRelationship child : result.getChildRelationships()) {
            if (child.getRelationshipName() != null) {
              childRelationships.put(child.getRelationshipName().toLowerCase(),
                  child.getChildSObject().toLowerCase());
            }
          }
          metadataMap.put(result.getName().toLowerCase(), new ObjectMetadata(fieldMap,
              relationshipMap, childRelationships));
        }
      }

      if (references != null) {
        for (List<Pair<String, String>> path : references) {
          // Top field name in the path should be in the metadata now
          if (!path.isEmpty()) {
            Pair<String, String> top = path.get(0);
            Field field = metadataMap.get(top.getLeft()).getFieldFromRelationship(top.getRight());
            Set<String> sobjectNames = metadataMap.keySet();
            for (String ref : field.getReferenceTo()) {
              ref = ref.toLowerCase();
              if (!sobjectNames.contains(ref) && !next.contains(ref)) {
                next.add(ref);
              }
              if (path.size() > 1) {
                path.set(1, Pair.of(ref, path.get(1).getRight()));
              }
            }
            // SDC-10422 Polymorphic references have an implicit reference to the Name object type
            if (field.isPolymorphicForeignKey()) {
              next.add(NAME);
            }
            path.remove(0);
          }
        }
      }
    }

    if (!next.isEmpty()) {
      getAllReferences(partnerConnection, metadataMap, references, next.toArray(new String[0]), depth - 1);
    }
  }
private void getAllReferences(
      PartnerConnection partnerConnection,
      Map<String, ObjectMetadata> metadataMap,
      List<List<Pair<String, String>>> references,
      String[] allTypes,
      int depth
  ) throws ConnectionException {
    if (depth < 0) {
      return;
    }

    List<String> next = new ArrayList<>();

    for (int typeIndex = 0; typeIndex < allTypes.length; typeIndex += MAX_METADATA_TYPES) {
      int copyTo = Math.min(typeIndex + MAX_METADATA_TYPES, allTypes.length);
      String[] types = Arrays.copyOfRange(allTypes, typeIndex, copyTo);

      // Special case - we prepopulate the cache with the root sobject type - don't repeat
      // ourselves
      if (types.length > 1 || !metadataMap.containsKey(types[0])) {
        for (DescribeSObjectResult result : partnerConnection.describeSObjects(types)) {
          Map<String, Field> fieldMap = new LinkedHashMap<>();
          Map<String, Field> relationshipMap = new LinkedHashMap<>();
          for (Field field : result.getFields()) {
            fieldMap.put(field.getName().toLowerCase(), field);
            String relationshipName = field.getRelationshipName();
            if (relationshipName != null) {
              relationshipMap.put(relationshipName.toLowerCase(), field);
            }
          }
          Map<String, String> childRelationships = new LinkedHashMap<>();
          for (ChildRelationship child : result.getChildRelationships()) {
            if (child.getRelationshipName() != null) {
              childRelationships.put(child.getRelationshipName().toLowerCase(),
                  child.getChildSObject().toLowerCase());
            }
          }
          metadataMap.put(result.getName().toLowerCase(), new ObjectMetadata(fieldMap,
              relationshipMap, childRelationships));
        }
      }

      if (references != null) {
        for (List<Pair<String, String>> path : references) {
          // Top field name in the path should be in the metadata now
          if (!path.isEmpty()) {
            Pair<String, String> top = path.get(0);
            Field field = metadataMap.get(top.getLeft()).getFieldFromRelationship(top.getRight());
            Set<String> sobjectNames = metadataMap.keySet();
            for (String ref : field.getReferenceTo()) {
              ref = ref.toLowerCase();
              if (!sobjectNames.contains(ref) && !next.contains(ref)) {
                next.add(ref);
              }
              if (path.size() > 1) {
                path.set(1, Pair.of(ref, path.get(1).getRight()));
              }
            }
            // SDC-10422 Polymorphic references have an implicit reference to the Name object type
            if (field.isPolymorphicForeignKey()) {
              next.add(NAME);
            }
            path.remove(0);
          }
        }
      }
    }

    if (!next.isEmpty()) {
      getAllReferences(partnerConnection, metadataMap, references, next.toArray(new String[0]), depth - 1);
    }
  }
infinite recursion