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>
74 lines
3.9 KiB
Java
74 lines
3.9 KiB
Java
// Measures the value a JavaBean getter returns on a freshly constructed object.
|
|
// XMLEncoder shares equal Integer and Boolean objects: an int written once as
|
|
// the result of a getter (`<void id="Integer0" property="iconTextGap"/>`) is
|
|
// later referenced by id — e.g. as a node's x coordinate. Decoding such a file
|
|
// needs these defaults; they are measured here, not guessed.
|
|
//
|
|
// The same holds for static constants: the first Integer 0 in a file may be
|
|
// written as `SwingConstants.CENTER`, and every later 0 refers to it.
|
|
//
|
|
// Usage: java -cp filius.jar:lib/*:classes GetterDefaults <output json> <fqcn#property | fqcn::FIELD>...
|
|
|
|
import java.beans.Introspector;
|
|
import java.beans.PropertyDescriptor;
|
|
import java.io.FileOutputStream;
|
|
import java.lang.reflect.Method;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Map;
|
|
import java.util.TreeMap;
|
|
|
|
public class GetterDefaults {
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
Map<String, Object> result = new TreeMap<>();
|
|
for (int index = 1; index < args.length; index++) {
|
|
String key = args[index];
|
|
if (key.contains("::")) {
|
|
String className = key.substring(0, key.indexOf("::"));
|
|
String field = key.substring(key.indexOf("::") + 2);
|
|
String simpleName = className.substring(className.lastIndexOf('.') + 1);
|
|
result.put(simpleName + "." + field, Class.forName(className).getField(field).get(null));
|
|
continue;
|
|
}
|
|
String className = key.substring(0, key.indexOf('#'));
|
|
String property = key.substring(key.indexOf('#') + 1);
|
|
String simpleName = className.substring(className.lastIndexOf('.') + 1);
|
|
try {
|
|
// 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()));
|
|
}
|
|
}
|
|
try (FileOutputStream out = new FileOutputStream(args[0])) {
|
|
out.write((FlsOracle.Json.write(result, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
System.out.println("getter defaults: " + result.size());
|
|
System.exit(0);
|
|
}
|
|
|
|
static Object read(Object target, String property) throws Exception {
|
|
Method getter = null;
|
|
for (PropertyDescriptor descriptor : Introspector.getBeanInfo(target.getClass()).getPropertyDescriptors()) {
|
|
if (descriptor.getName().equals(property)) getter = descriptor.getReadMethod();
|
|
}
|
|
if (getter == null) getter = target.getClass().getMethod(property);
|
|
Object value = getter.invoke(target);
|
|
if (value == null || value instanceof Number || value instanceof Boolean || value instanceof String) return value;
|
|
return Map.of("class", value.getClass().getName());
|
|
}
|
|
}
|