test(java-oracle): measure the getter defaults XMLEncoder refers to

XMLEncoder shares equal Integer objects, so a node's x coordinate can be
written as a reference to the result of JSidebarButton.getIconTextGap().
GetterDefaults constructs the classes like XMLDecoder does and records
what the getters return (packages/fls/src/javaDefaults.json).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 20:13:28 +00:00
co-authored by Claude Opus 5.5
parent 0c843dc3de
commit fc9d865820
4 changed files with 107 additions and 1 deletions
+55
View File
@@ -0,0 +1,55 @@
// 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.
//
// Usage: java -cp filius.jar:lib/*:classes GetterDefaults <output json> <fqcn#property>...
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];
String className = key.substring(0, key.indexOf('#'));
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);
} 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());
}
}