JML: A Beginner’s Guide to Java Modeling Language
What it is
- JML (Java Modeling Language) is a specification language for Java programs used to write formal, executable specifications—preconditions, postconditions, and invariants—directly in Java source as annotations or comments.
Why use it
- Document behavior precisely: Makes intended behavior explicit for developers and reviewers.
- Detect bugs early: Static and runtime tools can check that implementations meet specifications.
- Support verification: Enables formal proofs and automated reasoning about code correctness.
- Improve maintenance: Clear contracts reduce misunderstandings when modifying code.
Core concepts
- Preconditions (requires): Conditions that must hold when a method is called.
- Postconditions (ensures): Conditions guaranteed after method execution if preconditions held.
- Invariants: Conditions that must always hold for objects or classes (e.g., consistent internal state).
- History constraints and model fields: Abstract state used for specifying behavior not directly represented by fields.
- Pure methods and helper annotations: Mark methods that have no side effects or are only for specification.
Syntax overview (examples)
- Preconditions/postconditions are written as JML clauses in comments or annotations:
- //@ requires x >= 0;
- //@ ensuresesult >= 0;
- Invariants:
- //@ invariant balance >= 0;
- Assignable/modifies clause (what a method may modify):
- //@ assignable balance;
- Pure method:
- /@ pure @/ public int size();
Tooling
- Runtime assertion checkers (e.g., OpenJML runtime mode) — insert runtime checks from JML specs.
- Static checkers and verifiers (e.g., OpenJML, ESC/Java2 historically) — analyze code for spec violations.
- Test generation and documentation tools that use JML specs.
Getting started (practical steps)
- Install a JML toolset like OpenJML.
- Add simple specs to a small class (pre/postconditions and one invariant).
- Run runtime checks to see violations during tests.
- Gradually add specs and use static checks for deeper verification.
Best practices
- Start with high-level invariants and key method contracts.
- Keep specs readable and maintainable—use model fields for abstraction.
- Prefer simple, testable predicates; avoid overly complex logic in specs.
- Use pure/helper methods for repeated spec expressions.
Limitations
- Learning curve for formal specifications.
- Tool support varies; static verification can produce false positives/negatives.
- Runtime checks add overhead and may be less useful for low-level performance-critical code.
Further learning
- Hands-on: annotate a small Java project and run OpenJML.
- Read tutorials and the OpenJML documentation to learn tool-specific features.
Leave a Reply