Technische Universität München Fakultät für Informatik Vorlesung Softwaretechnik 1 Florian Hölzl, Markus Pister, Dr. Bernhard Rumpe WS 2002/2003 Merkblatt JML 19. Dezember 2002 www4.in.tum.de/~rumpe/se JML – the Java Modeling Language Die JML ist eine Erweiterung der Sprache Java um Konstrukte zur Spezifikation von Java-Programmen. Die wichtigsten Sprachelemente der JML sind auf diesem Blatt zusammengefasst. Dazu zählen neben Invarianten auch Beschreibungselemente für das Verhalten von Methoden (Vor- und Nachbedingungen, Ausnahmen, Prädikate). Installation und Aufruf von JML Im Web unter der Adresse [1] befindet sich eine aktuelle Fassung der JML, die heruntergeladen und ausgepackt werden kann. Weitere Informationen zu den installierten Dateien und zur Sprache JML finden Sie in der Datei JML.html. Für die Vorlesung sind hauptsächlich der Checker und der Compiler relevant, die folgende Aufrufsyntax haben (ggf. Aufrufpfade geeignet setzen): jml jmlc Liste von Datei.java Ordner .... Liste von Datei.java Ordner ... Testbeispiele zum Ausprobieren finden sich im Ordner org/. JML-Annotationen in Java-Quelltexten JML-Annotationen werden als spezielle Kommentare in den Quelltext eingefügt. Einzeilige Annotationen beginnen mit dem von Java bekannten Doppel-Slash gefolgt von einem Klammeraffen (//@). Mit /*@ und @*/ können Annotationen in den Java-Code eingebettet werden und mehrere Zeilen umfassen. Durch dieses Verfahren bleiben alle JMLDateien auch als Java-Dateien verwendbar. Invarianten (invariant, non_null) Invarianten werden in der JML durch das Schlüsselwort Invarianten gelten zu jedem Zeitpunkt. invariant public class InvariantDemo { //@ invariant aReference != null; public Object aReference; public InvariantDemo() { aReference = new Object(); } } Die obige Invariante kann auch mittels non_null kompakt formuliert werden: public /*@ non_null @*/ Object aReference; eingeleitet. Vorlesung Softwaretechnik 1 Merkblatt JML Verhaltensbeschreibungen (behavior, normal_behavior, exceptional_behavior, also, pure) Methoden ohne Seiteneffekte, können mittels pure gekennzeichnet werden, was zur Folge hat, dass sie in JML-Ausdrücken benutzt werden können. Andernfalls würde zum Beispiel die Auswertung einer Invarianten selbst eine Veränderung des Systems bewirken. Um das Verhalten von Methoden zu spezifizieren, stellt die JML mehrere Möglichkeiten zur Verfügung, die alternativ verwendet werden können. Eine Verhaltensbeschreibung beginnt im allgemeinen Fall mit dem Schlüsselwort behavior und steht im Quelltext vor der zu beschreibenden Methode. Um genauer anzugeben, welche Art von Verhalten definiert wird, stellt die JML die beiden Varianten normal_behavior und exceptional_behavior bereit. Letztere beschreibt das Verhalten im Ausnahmefall, wenn eine Exception als Ergebnis produziert wird. Attribute, die durch eine Methode verändert werden dürfen, müssen mittels assignable in der Verhaltensbeschreibung explizit angegeben werden. JML prüft, ob sich eine Implementierung daran hält. Eine wesentliche Eigenschaft dieser Angabe ist insbesondere, dass nicht erwähnte Attribute nicht verändert werden dürfen. Vorbedingungen von Methoden werden in JML durch requires P; und Nachbedingungen durch ensures P; spezifiziert. P ist dabei ein boolescher Ausdruck über den Attributen und Methodenparametern. Ein Exception-Ergebnis einer Methode wird durch signals (Ex e) P; beschrieben. Ex ist der Name der Exception; e ist ein optionaler Bezeichner der Ausnahme, welcher dann in P beschrieben werden kann. Die Nachbedingung einer Methode muss nur erfüllt sein, wenn die Vorbedingung erfüllt war. Werden zu einer Methode mehrere Verhaltensbeschreibungen angegeben, z.B. mit unterschiedlichen Vorbedingungen, so sind diese Beschreibungen durch das Schlüsselwort also zu verbinden. Es sind dann jeweils die Nachbedingungen zu erfüllen, deren Vorbedingung gegolten haben. public class BigBehaviorDemo { public int myInt = 0; /*@ public behavior @ requires (obj != null) && (i >= 0); @ assignable myInt; @ ensures (myInt == 5); @ @ also public normal_behavior @ requires (obj != null) && (i < 0) ; @ assignable myInt; @ ensures (myInt == getANumber()); @ @ also public exceptional_behavior @ requires (obj == null); @ signals (AnException); @ @*/ public void aMethod(Object obj, int i) throws AnException { if (obj == null) throw new AnException(); if (i < 0) myInt = getIntPure(); else myInt = 5; } /*@ public behavior @ requires true; @ ensures (0 <= \result && result <= 99); @ Seite 2 von 4 Vorlesung Softwaretechnik 1 Merkblatt JML @*/ public /*@ pure @*/ int getANumber(){ return 42; } } Quantoren (\forall, \exists) In prädikatenlogischen Aussagen können die mathematischen Quantoren \forall und \exists verwendet werden. Sie haben die Form: (<Quantor> <VariablenDeklarationen>; <Variablenbeschränkungen>; <Quantorenbedingung>) Beispiel: (\forall int i,j; 0<= i && i < j && j< sortedIntArray.length; sortedIntArray[i] <= sortedIntArray[j]) Damit wird es möglich, Eigenschaften für Sammlungen von Objekten zu beschreiben. Obiges Beispiel beschreibt, dass die Inhalte eines Arrays sortiert sind. Folgendes Beispiel beschreibt (im Kontext entsprechender Klassen), dass Personen unter 18 Eltern oder Vormund haben: (\forall Person p; p.age < 18; p.parents != null || (\exists Person vormund;;vormund.mündel==p) Prädikate (\result, \old, \nonnullelements) Das JML-Schlüsselwort \result bezieht sich in einer Aussage auf den Rückgabewert einer Methode und darf nur in ensures-Klauseln bei Methoden mit Ergebnistyp verwendet werden. Der Typ von \result entspricht dem Rückgabetyp der Methode. Damit kann das Ergebnis beschrieben werden. Das Schlüsselwort \old ist in Nachbedingungen (ensures- und signals-Klauseln) erlaubt. Ein Ausdruck der Form \old(Expr) bezieht sich auf den Wert von Expr zu Beginn der Ausführung der Methode. Variablen, die in Expr vorkommen haben darin ihren ursprünglichen Wert. Der Typ von \old(Expr) entspricht dem Typ von Expr. /*@ public behavior @ ensures (myInt == \old(myInt) + 1); @ @*/ public void addOneToMyInt() { myInt = myInt + 1; } Der Ausdruck \nonnullelements(myArray) ist eine Kurzform für folgende Aussage: (myArray != null) && (\forall int i; 0 <= i && i < myArray.length; myArray[i] != null) Seite 3 von 4 Vorlesung Softwaretechnik 1 Merkblatt JML Zugriffskontrolle (public, protected, private) Die JML besitzt für Invarianten die selben Schlüsselwörter zur Steuerung der Zugriffskontrolle wie Java. Bei Invarianten und Verhaltensbeschreibungen kann mittels public, protected und private bestimmt werden, welche Attribute und (pure) Methoden innerhalb der Invariante oder Verhaltensbeschreibung sichtbar sind, bzw. verwendet werden können. public class PrivacyDemo { public int pub; protected int prot; int def; private innt priv; invariant invariant invariant invariant // // // // //@ //@ //@ //@ public public public public //@ //@ //@ //@ protected protected protected protected invariant invariant invariant invariant //@ //@ //@ //@ invariant invariant invariant invariant pub > 0; prot > 0; def > 0; priv > 0; //@ //@ //@ //@ private private private private public protected package private private pub > 0; prot > 0; def > 0; priv > 0; invariant invariant invariant invariant pub > 0; prot > 0; def > 0; priv > 0; pub > 0; prot > 0; def > 0; priv > 0; // // // // ok FEHLER !!! FEHLER !!! FEHLER !!! // // // // ok ok FEHLER !!! FEHLER !!! // // // // ok ok ok FEHLER !!! // // // // ok ok ok ok } Weitere Informationsquellen [1] JML Homepage: http://www.cs.iastate.edu/~leavens/JML/index.html [2] G. Leavens, A. Baker, C. Ruby: JML: A Notation for Detailed Design ftp://ftp.cs.iastate.edu/pub/leavens/JML/jmlkluwer.pdf [3] G. Leavens, E. Poll, C. Clifton, Y. Cheon, C. Ruby: JML Reference Manual ftp://ftp.cs.iastate.edu/pub/leavens/JML/jmlrefman.pdf und natürlich die im JML-Paket beigelegten Beschreibungen. Seite 4 von 4