diff --git a/packages/fls/src/javaDefaults.json b/packages/fls/src/javaDefaults.json new file mode 100644 index 0000000..dba9c77 --- /dev/null +++ b/packages/fls/src/javaDefaults.json @@ -0,0 +1,17 @@ +{ + "DHCPServer#port": 67, + "DNSServer#port": 53, + "Gateway#maxLayerOfOperation": 2, + "JSidebarButton#debugGraphicsOptions": 0, + "JSidebarButton#displayedMnemonicIndex": -1, + "JSidebarButton#enabled": true, + "JSidebarButton#iconTextGap": 4, + "JSidebarButton#verticalTextPosition": 3, + "Notebook#maxLayerOfOperation": 4, + "RIPServer#port": 520, + "Rechner#maxLayerOfOperation": 4, + "ServerBaustein#port": 55555, + "ThreadGroup#maxPriority": 10, + "Vermittlungsrechner#maxLayerOfOperation": 2, + "WebServer#port": 80 +} diff --git a/tools/java-oracle/README.md b/tools/java-oracle/README.md index 6491ce4..56a3e9f 100644 --- a/tools/java-oracle/README.md +++ b/tools/java-oracle/README.md @@ -22,3 +22,15 @@ virtuellen Bildschirm statt „headless". * Bisher ausgelesen: Geräte (Klasse, Name, Beschriftung, Position, Schnittstellen), Kabel (Enden als Gerät/Schnittstelle), Doku-Elemente. Systemsoftware, Dateisysteme und Anwendungen folgen schrittweise. + +## Getter-Standardwerte + +XMLEncoder teilt gleiche `Integer`/`Boolean`-Objekte. Ein Wert, der einmal als +Ergebnis eines Getters geschrieben wurde (``), taucht später nur noch als Verweis auf — etwa als +x-Koordinate eines Geräts. Daran scheitert der Swift-Leser (Plan §13, M2). + +`GetterDefaults` erzeugt die betroffenen Klassen wie XMLDecoder (ohne +Argumente) und ruft den Getter auf; das Ergebnis steht in +`packages/fls/src/javaDefaults.json`. Gemessen, nicht geraten: Filius' Knopf +setzt `verticalTextPosition` auf 3 (BOTTOM), nicht auf Swings 0 (CENTER). diff --git a/tools/java-oracle/run.sh b/tools/java-oracle/run.sh index 24e8fa4..0b3cb8a 100755 --- a/tools/java-oracle/run.sh +++ b/tools/java-oracle/run.sh @@ -21,7 +21,7 @@ if [ ! -f "$upstream/target/filius.jar" ]; then fi classpath="$upstream/target/filius.jar:$upstream/target/lib/*" mkdir -p "$here/.build" -javac -d "$here/.build" -cp "$classpath" "$here/src/FlsOracle.java" +javac -encoding UTF-8 -d "$here/.build" -cp "$classpath" "$here/src/FlsOracle.java" "$here/src/GetterDefaults.java" # FILIUS writes its settings below $HOME; keep them out of the real one. mkdir -p "$here/.build/home" # Removed first: a crashed run must not leave the previous result standing. @@ -29,3 +29,25 @@ rm -f "$root/corpus/corpus.java.json" HOME="$here/.build/home" xvfb-run -a java -cp "$classpath:$here/.build" FlsOracle \ "$root/corpus" "$root/corpus/corpus.java.json" 2>&1 | grep -v 'logback\|^$' || true test -s "$root/corpus/corpus.java.json" + +# Getter defaults for the XMLEncoder references (packages/fls/src/javaDefaults.json). +defaults="$root/packages/fls/src/javaDefaults.json" +rm -f "$defaults" +HOME="$here/.build/home" xvfb-run -a java -cp "$classpath:$here/.build" GetterDefaults "$defaults" \ + filius.gui.netzwerksicht.JSidebarButton#iconTextGap \ + filius.gui.netzwerksicht.JSidebarButton#verticalTextPosition \ + filius.gui.netzwerksicht.JSidebarButton#displayedMnemonicIndex \ + filius.gui.netzwerksicht.JSidebarButton#debugGraphicsOptions \ + filius.gui.netzwerksicht.JSidebarButton#enabled \ + java.lang.ThreadGroup#maxPriority \ + filius.hardware.knoten.Rechner#maxLayerOfOperation \ + filius.hardware.knoten.Notebook#maxLayerOfOperation \ + filius.hardware.knoten.Vermittlungsrechner#maxLayerOfOperation \ + filius.hardware.knoten.Gateway#maxLayerOfOperation \ + filius.software.clientserver.ServerBaustein#port \ + filius.software.dhcp.DHCPServer#port \ + filius.software.dns.DNSServer#port \ + filius.software.rip.RIPServer#port \ + filius.software.www.WebServer#port \ + 2>&1 | grep -v 'logback\|^$' || true +test -s "$defaults" diff --git a/tools/java-oracle/src/GetterDefaults.java b/tools/java-oracle/src/GetterDefaults.java new file mode 100644 index 0000000..b66a606 --- /dev/null +++ b/tools/java-oracle/src/GetterDefaults.java @@ -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 (``) 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 ... + +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 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()); + } +}