public static <ModelA, ModelB> void replicateModelHierarchy(
    @NotNull ModelA rootModelA,
    @NotNull Function<@NotNull ModelA, @Nullable ModelB> getModel,
    @NotNull Function<@NotNull ModelA, @NotNull Collection<? extends @NotNull ModelA>> getChildModel,
    @NotNull BiConsumer<@NotNull ModelB, @NotNull ModelB> addChildModel
  ) {
    ModelB rootModelB = getModel.apply(rootModelA);
    if (rootModelB == null) return;

    Queue<Pair<ModelA, ModelB>> queue = new ArrayDeque<>();
    queue.add(new Pair<>(rootModelA, rootModelB));

    while (!queue.isEmpty()) {

      Pair<ModelA, ModelB> parentModel = queue.remove();
      ModelA parentModelA = parentModel.getFirst();
      ModelB parentModelB = parentModel.getSecond();

      for (ModelA childModelA : getChildModel.apply(parentModelA)) {

        ModelB childModelB = getModel.apply(childModelA);
        if (childModelB == null) continue;

        queue.add(new Pair<>(childModelA, childModelB));

        addChildModel.accept(parentModelB, childModelB);
      }
    }
  }
public static <ModelA, ModelB> void replicateModelHierarchy(
    @NotNull ModelA rootModelA,
    @NotNull Function<@NotNull ModelA, @Nullable ModelB> getModel,
    @NotNull Function<@NotNull ModelA, @NotNull Collection<? extends @NotNull ModelA>> getChildModel,
    @NotNull BiConsumer<@NotNull ModelB, @NotNull ModelB> addChildModel
  )