fix(fls): Gnutella's peer limit is random in Java, not a default

PeerToPeerAnwendung's constructor rolls its peer limit (3, 4 or 5). The
getter defaults measured it once each run — 4, then 5 — and c48d15d
committed 5 as a default. GetterDefaults now constructs every class 64
times and writes a value that varies as {"random": [...]}; the decoder
answers a reference to it as unresolved, and the topology layer reports
a peer limit the file does not set as null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 06:12:14 +00:00
co-authored by Claude Opus 5.5
parent c48d15def4
commit 8080e7dcb2
6 changed files with 65 additions and 17 deletions
+14 -6
View File
@@ -34,12 +34,20 @@ public class GetterDefaults {
String property = key.substring(key.indexOf('#') + 1);
String simpleName = className.substring(className.lastIndexOf('.') + 1);
try {
Object value = className.equals("java.lang.ThreadGroup")
// A Thread's uncaughtExceptionHandler is its group; XMLDecoder runs
// in the main thread, so that is the group asked.
? read(Thread.currentThread().getThreadGroup(), property)
: read(Class.forName(className).getDeclaredConstructor().newInstance(), property);
result.put(simpleName + "#" + property, value);
// Constructed many times: a constructor may roll its value (Gnutella's
// peer limit is 3, 4 or 5 at random). Such a value is no default and is
// written as {"random": [the values seen]}.
java.util.TreeSet<String> seen = new java.util.TreeSet<>();
Object value = null;
for (int attempt = 0; attempt < 64; attempt++) {
value = className.equals("java.lang.ThreadGroup")
// A Thread's uncaughtExceptionHandler is its group; XMLDecoder runs
// in the main thread, so that is the group asked.
? read(Thread.currentThread().getThreadGroup(), property)
: read(Class.forName(className).getDeclaredConstructor().newInstance(), property);
seen.add(String.valueOf(value));
}
result.put(simpleName + "#" + property, seen.size() == 1 ? value : Map.of("random", new java.util.ArrayList<>(seen)));
} catch (Throwable error) {
Throwable cause = error.getCause() != null ? error.getCause() : error;
result.put(simpleName + "#" + property, Map.of("error", cause.toString()));