| 81 | try { |
| 82 | this.addProblemUrl(); |
| 83 | // TODO Remove try-catch block in 2025; we very specifically want to avoid a case where something |
| 84 | // causes an exception and prevents the exception from being reported. |
| 85 | // I think this is unnecessary, but it is better to be paranoid here. |
| 86 | } catch (Exception e) { |
| 87 | this.getCause().addSuppressed(e); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Check to see if the {@link NetworkManager} has any errors related to this exception |
| 93 | * @since xxx |
| 94 | */ |
| 95 | private void addProblemUrl() { |
| 96 | final String urls = NetworkManager.getNetworkErrors().entrySet().stream() |
| 97 | .filter(entry -> mayHaveCaused(new HashSet<>(), this, entry.getValue())) |
| 98 | .map(Map.Entry::getKey) |
| 99 | .map(TextUtils::stripUrl) |
| 100 | .collect(Collectors.joining("\n")); |
| 101 | if (!Utils.isBlank(urls)) { |
| 102 | put("urls", urls); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Check if the other throwable may have caused this exception |
| 108 | * @param visited The exceptions visited so far for {@code other}. This should (hopefully) avoid issues where |
| 109 | * someone has the bright idea of suppressing an exception using an exception that it suppressed. |
| 110 | * @param throwable The current throwable to check |
| 111 | * @param other The other exception to check |
| 112 | * @return {@code true} if the other exception is in this exceptions stack |
| 113 | */ |
| 114 | private static boolean mayHaveCaused(Set<Throwable> visited, Throwable throwable, Throwable other) { |
| 115 | Throwable current = throwable; |
| 116 | while (current != null) { |
| 117 | if (current == other) { |
| 118 | return true; |
| 119 | } |
| 120 | visited.add(current); |
| 121 | for (Throwable suppressed : current.getSuppressed()) { |
| 122 | if (mayHaveCaused(visited, suppressed, other)) { |
| 123 | return true; |
| 124 | } |
| 125 | } |
| 126 | current = current.getCause(); |
| 127 | } |
| 128 | return false; |