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:
@@ -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 (`<void id="Integer0"
|
||||
property="iconTextGap"/>`), 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).
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user