Files
mdg-filius/tools/java-oracle/src/GetterDefaults.java
T
julian.kiedaischandClaude Opus 5.5 a02bb62413 feat(fls): topology of a .fls file as Java loads it
readTopology maps the decoded JavaBeans graph to devices, cables and
documentation items the way SzenarioVerwaltung.netzwerkLaden does: the
kind from the Java class (the palette label is not file data), devices
without bounds at 0,0, interface values through Java's setters. All 23
corpus files match Java field by field.

Found on the way:
- listItems mixed a constructor's elements with added ones; a router's
  second interface was lost. Lists now replay add/set in order after the
  elements the constructor made.
- The first 0 of a file may be SwingConstants.CENTER; measured like the
  getter defaults.
- IP.ipCheck (javaIp.ts) measured on 46 cases: empty tokens skipped,
  signs, leading zeros and BMP digits of any script accepted.
- The Java oracle took lower-case MACs in a file for random ones (8
  interfaces); it now compares case-insensitively and reports the host
  name flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:33:02 +00:00

66 lines
3.3 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 {
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());
}
}