Three Java packages, a binding onto the reusable transport, and both layers under contract.
cd examples/todo-java
blabla finish
prepare compiles Main.java, the three packages and adapters/java/blabla/Adapter.java into
.blabla/classes, which is outside the tree BlaBla fingerprints, and command launches
java -cp .blabla/classes Main. startup_ms is 5000 while timeout_ms stays at 1000, because a
JVM start is not a response. A JDK on PATH is all it needs; structural analysis needs none, since
the provider parses source text.
Two defects that the structure contract could not see, both in this example's own code:
- A todo whose text contained a newline did not survive a restart.
TodoStorewrites one tab-separated record per line, so a newline in the text split the record in two on read. The minimized counterexample was two actions —add("\"\\\n")thenrestart()— and the store now escapes its own delimiters. - A legal call was refused. The transport read a whole number into a Java
int, and BlaBla'sintis 64-bit: the generator reached9007199254740991, which saturated toInteger.MAX_VALUEand came back as{"ok": false}, which BlaBla correctly reported as an application failure rather than a passing case.Args.integerreturnslong, andTodo.idis alongwith it.
Neither was reachable while this example carried a structure contract alone.
todo-java.bla covers the provider's whole supported surface against real, idiomatic source:
- types and members at one level:
Todo.id,Todo.completed,TodoStore.load,TodoApp.add. - static final collections:
Todo.FIELDScontains"id","text"and"done";TodoApp.ACTIONScontains"add","complete"and"remove". - cross-package imports resolved to declared modules:
appdepends onstoreand onmodel, andstoredepends onmodel, each through a single-type import matched against that module'spackagedeclaration and file stem. - an external dependency:
storedepends onjava.nio.file.Files. - the layering, as
forbidrules: the model reaches neither the store nor the application and touches no filesystem, and the store does not reach the application. - the split between application and transport, as a requirement:
Mainbinds the application and launches the transport, the transport declaresAdapter.serve,Adapter.action,Adapter.ArgsandAdapter.LINE_LIMIT, andforbidrules keep a protocol loop out ofTodoAppand any todo or store out of the transport.dependency entry -> transportis deliberately absent: the transport lies outside this project root, so that fact cannot be observed, andblabla check --falsifyreports such a rule as VACUOUS rather than letting it stand.
The classpath, reflection, annotation processing, generics and overload resolution. Two cases are
reported as unknown rather than absent, because Java can hide a reference from static reading: a
wildcard import import a.b.*;, which could supply any type in that package, and a reference between
two types in the same package, which needs no import at all. Each unknown names the declared module
it could be hiding, so it makes the rules over that one target ERROR and leaves every other
dependency on the file decidable. This example keeps its three types in three different packages, so
neither case arises here; both are covered by the provider's own tests.