static boolean linksEqual(@Nullable ActionLink o1, @Nullable ActionLink o2) {
    if (o1 == null || o2 == null) return o1 == o2;
    if (o1.getClass() != o2.getClass()) return false;
    if (!Objects.equals(o1.getText(), o2.getText())) return false;

    if (o1 instanceof MyActionLink a1 && o2 instanceof MyActionLink a2) {
      return a1.external == a2.external &&
             // do not require equals/hashCode for Runnables
             a1.linkAction.getClass() == a2.linkAction.getClass();
    }
    else if (o1 instanceof BrowserLink b1 && o2 instanceof BrowserLink b2) {
      return b1.getUrl().equals(b2.getUrl());
    }
    return o1 == o2;
  }
static boolean linksEqual(@Nullable ActionLink o1, @Nullable ActionLink o2)