13.07.2015 Aufrufe

Design By Contract in Java Seminarbericht WS06 ... - Dominik Gruntz

Design By Contract in Java Seminarbericht WS06 ... - Dominik Gruntz

Design By Contract in Java Seminarbericht WS06 ... - Dominik Gruntz

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>Sem<strong>in</strong>arbericht <strong>WS06</strong>/07Fachhochschule NordwestschweizHochschule für TechnikStudiengang InformatikSem<strong>in</strong>arbericht vonMatthias HausherrBetreuender DozentProf. Dr. Dom<strong>in</strong>ik <strong>Gruntz</strong>W<strong>in</strong>disch, 15. November 2006


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>AbstractDie Idee von <strong>Design</strong> <strong>By</strong> <strong>Contract</strong> (DBC) ist, so exakt wie möglich zu def<strong>in</strong>ieren, was e<strong>in</strong>Softwaremodul tun soll. Die Bedeutung e<strong>in</strong>er ausführlichen Spezifikation für Software kannkaum stark genug betont werden. Wartungskosten machen e<strong>in</strong>en grossen Teil der Kosten imLebenszyklus e<strong>in</strong>er Software aus und präzise Spezifikation und Dokumentation hilft mit,diese Kosten zu senken. <strong>Design</strong> <strong>By</strong> <strong>Contract</strong> treibt diese Idee auf die Spitze: Es wird soexakt wie möglich def<strong>in</strong>iert, was das Softwaremodul tun soll. Die Firma Eiffel, quasi dieErf<strong>in</strong>der von <strong>Design</strong> <strong>By</strong> <strong>Contract</strong>, beschreibt ihre Motivation unter anderem mit folgendemSatz:“If we don't state what a module should do, there is little likelihood that it will do it.”- Eiffel.comIm ersten Teil dieses Berichtes wird erläutert wie <strong>Design</strong> <strong>By</strong> <strong>Contract</strong> funktioniert und welcheZiele damit verfolgt werden. Im zweiten Teil werden die Assertions, die seit JDK 1.4 von <strong>Java</strong>angeboten werden, näher betrachtet. Anschliessend wird <strong>in</strong> e<strong>in</strong>em Kapitel Ref<strong>in</strong>emente<strong>in</strong>geführt, welches erläutert, wie Vererbung und <strong>Design</strong> <strong>By</strong> <strong>Contract</strong> zusammenspielen. AlsKernstück des Berichtes werden zwei verschiedene <strong>Design</strong> <strong>By</strong> <strong>Contract</strong> Implementationenfür <strong>Java</strong> vorgestellt und kle<strong>in</strong>e Codesnippets präsentiert. Abschliessend wird e<strong>in</strong>eEmpfehlung zum E<strong>in</strong>satz von <strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong> abgegeben.Matthias Hausherr Seite 2 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>Inhaltsverzeichnis1. Der Ansatz <strong>Design</strong> <strong>By</strong> <strong>Contract</strong>...................................................................................... 41.1. Def<strong>in</strong>ition................................................................................................................ 41.2. Entstehung............................................................................................................. 41.3. Idee und DBC-Begriffe........................................................................................... 41.4. Hauptziele.............................................................................................................. 51.4.1. Steigerung der Qualität .................................................................................. 51.4.2. <strong>Contract</strong>s als Dokumentation ......................................................................... 51.4.3. Debugg<strong>in</strong>g und Test<strong>in</strong>g Hilfe .......................................................................... 52. <strong>Java</strong> Assertions.............................................................................................................. 62.1. Das Assert Statement ............................................................................................ 62.2. Verwendungszweck ............................................................................................... 62.3. Assertions und DBC............................................................................................... 63. Ref<strong>in</strong>ement (<strong>Contract</strong> Inheritance <strong>in</strong> DBC)...................................................................... 73.1. Regeln ................................................................................................................... 73.2. Beispiel .................................................................................................................. 74. Erweiterte Assertion Support Implementationen............................................................. 84.1. Erläuterung zu den Codebeispielen ....................................................................... 84.2. Erläuterung zu den Ref<strong>in</strong>ement Codebeispielen .................................................... 94.3. Jass ......................................................................................................................104.3.1. Facts .............................................................................................................104.3.2. Beschreibung ................................................................................................104.3.3. Syntaktische Elemente..................................................................................114.3.4. <strong>Java</strong>Doc Erweiterung ....................................................................................134.3.5. Ref<strong>in</strong>ement....................................................................................................134.3.6. Codebeispiel .................................................................................................144.3.7. Ref<strong>in</strong>ement Codebeispiel ..............................................................................154.4. C4J .......................................................................................................................164.4.1. Facts .............................................................................................................164.4.2. Beschreibung ................................................................................................164.4.3. Framework Elemente ....................................................................................174.4.4. Ref<strong>in</strong>ement....................................................................................................174.4.5. Codebeispiel .................................................................................................184.4.6. Ref<strong>in</strong>ement Codebeispiel ..............................................................................205. Empfehlung...................................................................................................................216. Quellenangaben............................................................................................................22Matthias Hausherr Seite 3 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>1. Der Ansatz <strong>Design</strong> <strong>By</strong> <strong>Contract</strong>1.1. Def<strong>in</strong>ition<strong>Design</strong> <strong>By</strong> <strong>Contract</strong>, abgekürzt DBC, oder Programm<strong>in</strong>g <strong>By</strong> <strong>Contract</strong> ist e<strong>in</strong> Ansatz umSoftware zu entwerfen.Der Ansatz beschreibt, dass der Software Eng<strong>in</strong>eer formale und messbare Conditions anSchnittstellen anknüpft, im S<strong>in</strong>ne e<strong>in</strong>es Vertrages zwischen Client und Server. DieseConditions werden zusätzlich zu den von der Programmiersprache verwendetenSicherungsmethoden (z.B. Typenkontrolle) verwendet und ermöglichen e<strong>in</strong>e semantischePrüfung und damit sehr präzis def<strong>in</strong>ierte Schnittstellen.1.2. EntstehungDer geistige Vater des DBC ist Bertrand Meyer (geborenim Jahre 1950 <strong>in</strong> Frankreich). Prof. Meyer ist vor allemdeshalb vielen Informatikern e<strong>in</strong> Begriff, weil er um 1985die Sprache Eiffel entwickelt hat, die DBC konsequentverwendet. Prof. Meyer legt den Fokus auf Qualität undgeht davon aus, dass darauf automatisch auch e<strong>in</strong>e hoheProduktivität folgt.Bertrand Meyer hat se<strong>in</strong>en Bachelor <strong>in</strong> Eng<strong>in</strong>eer<strong>in</strong>g ander École Polytechnique <strong>in</strong> Paris, se<strong>in</strong>en Master <strong>in</strong>Standford und den Ph. D. an der Université de Nancyabsolviert.Heute arbeitet Meyer an der ETHZ im Bereich SoftwareEng<strong>in</strong>eer<strong>in</strong>g. Diplom- und Bachelorabgänger derFachhochschule Nordwestschweiz, die den Mastermachen möchten, haben also die Möglichkeit, bei HerrMeyer im Rahmen e<strong>in</strong>es Masterstudiums diverseSoftware Eng<strong>in</strong>eer<strong>in</strong>g Kurse zu besuchen und somit DBCaus erster Hand zu lernen.Prof. Bertrand Meyer1.3. Idee und DBC-BegriffeDie Idee des <strong>Contract</strong>s zwischen Client und Server stammt aus dem Geschäftsleben: Zuersterklärt sich der Kunde bereit, dem Dienstleister e<strong>in</strong>e gewisse Summe zu zahlen (entsprichtObligation des Clients). Der Dienstleister wiederum verpflichtet sich dem Kunden dafür etwasBestimmtes zu liefern (entspricht Obligation des Servers). Dieses Schema wird nun auf denSoftware Eng<strong>in</strong>eer<strong>in</strong>g Prozess übertragen.Der Server (z.B. e<strong>in</strong>e Methode oder e<strong>in</strong> Modul) bestimmt sogenannte Preconditions. Diesestellen Bed<strong>in</strong>gungen bzw. Obligationen dar, die der Client des Servers erfüllen muss undjeweils vor Ausführung des Server Codes geprüft werden. Der Vorteil für den Server liegtdar<strong>in</strong>, dass er sich nicht mit Fällen ausserhalb der Precondition befassen muss. E<strong>in</strong>denkbares Beispiel hierfür wäre e<strong>in</strong> gültiger Wertebereich für e<strong>in</strong>e Integer Variable.Im Gegensatz zu den Preconditions werden die Postconditions jeweils nach der Ausführungdes Server Codes geprüft und müssen vom Server selber erfüllt werden. Sie stellenBed<strong>in</strong>gungen bzw. Obligationen dar, die der Server erfüllen muss und garantieren demAufrufer, dass gewisse Arbeiten verrichtet wurden. Oft greifen Postconditions dabei aufWerte zu, die vor der Ausführung der Methode galten.Matthias Hausherr Seite 4 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>Zusätzlich zu Pre- und Postconditions spielen Invariants e<strong>in</strong>e Rolle. Invariants sorgen dafür,dass bei E<strong>in</strong>tritts- und Austrittspunkten des Server Codes gewisse Conditions erfüllt bzw.Zustände gewahrt s<strong>in</strong>d. Invariants s<strong>in</strong>d <strong>in</strong> gewisser Weise also Pre- und Postconditions.Pre- und Postconditions sowie Invariants bilden e<strong>in</strong>en <strong>Contract</strong> zwischen Client und Server.Der <strong>Contract</strong> selber ist die Formalisierung der Conditions die beide Seiten erfüllen müssen.Der Entwickler, der den <strong>Contract</strong> entwirft, muss sich sehr genau Gedanken machen, was derServer erwartet (Preconditions), was er liefert bzw. garantiert (Postconditions) und was derServer unterhaltet (Invariants). Die <strong>Contract</strong>s stellen auch e<strong>in</strong> Teil der Dokumentation dar,sie dokumentieren nämlich das Verhalten der e<strong>in</strong>zelnen Software Komponenten.Durch E<strong>in</strong>satz von DBC entsteht e<strong>in</strong>e Kette von Verträgen, die schlussendlich für robustereSoftware sorgt. Wenn jedes e<strong>in</strong>zelne Element der Kette garantieren kann, die Postconditionzu erfüllen sofern die Precondition e<strong>in</strong>gehalten wurde, so entstehen weniger Fehler durchfalsche Annahmen seitens der Entwickler.E<strong>in</strong> Pr<strong>in</strong>zip des DBC ist es, e<strong>in</strong> Programm bei Nichte<strong>in</strong>haltung e<strong>in</strong>es <strong>Contract</strong>s sofort zuterm<strong>in</strong>ieren. Die Idee dah<strong>in</strong>ter ist es, das die Probleme sofort angegangen werden und nichtauf die lange Bank geschoben werden. Somit kann es nicht passieren, dass e<strong>in</strong> Bug, dessenBehebung man auf später verschoben hat, vergessen wird und somit als Bug im Endproduktlandet. Während des Deployment selber werden die <strong>Contract</strong>s oft ausgeschaltet. E<strong>in</strong>erseitsmöchte man unter Umständen e<strong>in</strong> Programmabbruch im Problemfall verh<strong>in</strong>dern undandererseits lässt sich damit die Performance erhöhen.1.4. Hauptziele1.4.1. Steigerung der QualitätUm die Reliability der Software zu verbessern sollte man Schnittstellen sehr genaudef<strong>in</strong>ieren. DBC zw<strong>in</strong>gt den Software Eng<strong>in</strong>eer dies schon früh im <strong>Design</strong> Prozess zu tun.Durch diese exakten Spezifikationen, welche Aufgaben e<strong>in</strong> Softwaremodul hat und welchePreconditions es stellt, erhöht sich auch die Wahrsche<strong>in</strong>lichkeit, dass es diesenAnforderungen später auch gerecht wird. Die Umkehrung dieser Überlegung ist ebenfallse<strong>in</strong>leuchtend: Wenn wir nicht genau spezifizieren was e<strong>in</strong> Modul tun soll, so wird es kaumdas Richtige tun.1.4.2. <strong>Contract</strong>s als DokumentationDas API e<strong>in</strong>es Softwaremoduls entspricht e<strong>in</strong>em <strong>Contract</strong> zwischen Client und Server. AlleObligationen und Rechte müssen öffentlich ersichtlich se<strong>in</strong>.Um Inkonsistenzen zwischen Source und Dokumentation zu vermeiden ist es zudem wichtig,dass das API direkt aus dem Source generiert wird. Ähnlich wie <strong>Java</strong> dieses Pr<strong>in</strong>zip mit<strong>Java</strong>Doc umsetzt, sollen auch die <strong>Contract</strong>s durch generierte Dokumentation beschriebenwerden. Bereits Eiffel hatte hierfür e<strong>in</strong> entsprechendes Tool, das aus dem Sourceautomatisch e<strong>in</strong>e entsprechende Dokumentation <strong>in</strong>klusive <strong>Contract</strong>s generiert. Ziel ist es,den Fokus der Entwickler auf die Schnittstellen zu lenken.1.4.3. Debugg<strong>in</strong>g und Test<strong>in</strong>g HilfeDank <strong>Contract</strong>s können potentielle Fehler früh aufgedeckt werden. Wird e<strong>in</strong> <strong>Contract</strong>gebrochen, wird das Programm sofort mit e<strong>in</strong>er Exception term<strong>in</strong>iert und der Fehler für denEntwickler schnell ersichtlich. Durch DBC lassen sich viele abnormale Fälle <strong>in</strong> e<strong>in</strong>er Artbehandeln, die Exception Handl<strong>in</strong>g vere<strong>in</strong>fachen und Fehlerquellen elim<strong>in</strong>ieren.Matthias Hausherr Seite 5 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>2. <strong>Java</strong> AssertionsSchon früh gab es Entwickler die DBC Support im JDK forderten. Dieser Wunsch stand anzweiter Stelle auf der Request For Enhancement Liste auf bugs.sun.com. Mit <strong>Java</strong> 1.4 wurdeschliesslich das assert Statement zur Verfügung gestellt und der Request geschlossen.Dieser Abschnitt beleuchtet <strong>Java</strong> Assertions und weshalb diese ke<strong>in</strong>e Implementation von<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> darstellen.2.1. Das Assert StatementAssert Statements prüfen gewisse Conditions und s<strong>in</strong>d entweder true oder false. Wird z.B.die Prüfung e<strong>in</strong>er Inputvariable vergessen, so kann es unter Umständen passieren, dass dasProgramm vorerst weiterläuft, dann aber an e<strong>in</strong>em späteren Punkt zur Runtime abstürzt. Umdies zu verh<strong>in</strong>dern kann man mit e<strong>in</strong>em assert Statement früh e<strong>in</strong>e gewünschte Conditionprüfen. E<strong>in</strong> mögliches Beispiel e<strong>in</strong>er Prüfung e<strong>in</strong>es Inputparameters:public <strong>in</strong>t temp(double t) {assert(-273.15 >= t): "Temperature must be greater than -273.15";// Weiterführender Code …}Resultiert e<strong>in</strong> false aus der Assertion, so bricht das Programm mit e<strong>in</strong>emjava.lang.AssertionError ab.2.2. VerwendungszweckAssertions s<strong>in</strong>d <strong>in</strong> erster L<strong>in</strong>ie e<strong>in</strong> Mittel zur frühen Detektion von Fehlern während derSoftware Entwicklung. Assertions s<strong>in</strong>d syntaktisch e<strong>in</strong>fach gestrickt und erlauben demEntwickler deshalb zügig und ohne grossen Overhead se<strong>in</strong>e Annahmen als Conditions zucodieren. Was auf den ersten Blick nicht allzuwichtig ersche<strong>in</strong>t, stellt e<strong>in</strong>e wesentliche Hilfebei der frühen Lokalisation von Bugs dar.E<strong>in</strong> Vorteil von Assertions gegenüber üblichen if-Anweisungen ist die Möglichkeit Assertionszu deaktiveren. Bei deaktivierten Assertions werden die assert Anweisungen nichtausgewertet und es entsteht ke<strong>in</strong>e Effizienze<strong>in</strong>busse.AssertionErrors haben etwa die gleiche Bedeutung wie RuntimeExceptions. Es ist wichtig zuunterscheiden zwischen den unchecked AssertionErrors bzw. RuntimeExceptions und denchecked Exceptions die deklariert und behandelt werden müssen. Assertions s<strong>in</strong>d per default<strong>in</strong> JDK 1.5 disabled. Mit den VM tag –ea oder –enableassertions kann man diese aktivieren.Da man Assertions e<strong>in</strong>fach deaktivieren kann eignen sie sich nicht für produktiven Code.E<strong>in</strong> Vorteil von Exceptions gegenüber Assertions ist die Möglichkeit, e<strong>in</strong> Exception Handl<strong>in</strong>gzu def<strong>in</strong>ieren für abnormale Fälle, von denen man weiss, dass sie e<strong>in</strong>treten und behandeltwerden können.2.3. Assertions und DBCWie man leicht erkennen kann, s<strong>in</strong>d Assertions <strong>in</strong> <strong>Java</strong> sehr e<strong>in</strong>geschränkt. Preconditions,Postconditions und Invariants werden als solche nicht unterstützt und lassen sich mit demassert Statement allenfalls etwas leichter abbilden. Wer DBC <strong>in</strong> <strong>Java</strong> verwenden möchte istgezwungen, auf andere Lösungen zurückzugreifen.Wer möchte, dass Sun DBC <strong>in</strong> <strong>Java</strong> <strong>in</strong>tegriert wird, kann an der Diskussion des Bug mit ID4449383 und Subjekt „Support For <strong>Design</strong> by <strong>Contract</strong>, beyond a simple assertion facility“auf bugs.sun.com teilnehmen und mehr dazu erfahren (L<strong>in</strong>k siehe Quellenangaben).Matthias Hausherr Seite 6 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>3. Ref<strong>in</strong>ement (<strong>Contract</strong> Inheritance <strong>in</strong> DBC)3.1. RegelnIst e<strong>in</strong>e Basisklasse an e<strong>in</strong>en <strong>Contract</strong> gebunden, wird der <strong>Contract</strong> automatisch an alleSubklassen vererbt. Die Subklasse kann fakultativ zusätzliche <strong>Contract</strong>s def<strong>in</strong>ieren.Für die Vererbung von <strong>Contract</strong>s gelten e<strong>in</strong>ige Regeln und Überlegungen:1. Die Precondition der Subklasse darf nicht strenger se<strong>in</strong> als die Precondition derBasisklasse (entspricht e<strong>in</strong>er logischen OR Verknüpfung). Damit wird sichergestellt,dass e<strong>in</strong> Zustand der die Precondition der Basisklasse erfüllt auch die Preconditionder Subklasse erfüllt.2. Die Postcondition der Subklasse darf nicht schwächer se<strong>in</strong> als die Postcondition derBasisklasse (entspricht e<strong>in</strong>er logischen AND Verknüpfung). Damit wird sichergestellt,dass e<strong>in</strong> Zustand der die Postcondition der Subklasse erfüllt auch die Postconditionder Basisklasse erfüllt.3. E<strong>in</strong>e Subklasse übernimmt den Invariant der Basisklasse und hat diese zu erfüllen.Diese Regeln sorgen dafür, dass e<strong>in</strong>e Subklasse den <strong>Contract</strong> der Basisklasse e<strong>in</strong>hält undvielleicht sogar verbessert (mehr dazu im Folgeabschnitt Beispiel). Wie vom Liskov’schenSubstitutionspr<strong>in</strong>zip vorgeschrieben darf überall wo e<strong>in</strong>e Basisklasse erwartet wird auch e<strong>in</strong>eSubklasse deren e<strong>in</strong>gesetzt werden. Die obigen Regeln ermöglichen e<strong>in</strong>e Handhabung wiees sich <strong>Java</strong> Entwickler gewohnt s<strong>in</strong>d, z.B. mit dem Statement BaseClass myBaseClass= new SubClass( );3.2. BeispielDas folgende Beispiel zeigt auf, dass es s<strong>in</strong>nvoll se<strong>in</strong> kann die Precondition <strong>in</strong> der Subklassegegenüber jener der Basisklasse zu schwächen. In diesem Beispiel kann mit der MethodeaddElement der Klasse Buffer e<strong>in</strong> Objekt e<strong>in</strong>em limitierten Buffer h<strong>in</strong>zugefügt werden. DieMethode kann nur aufgerufen werden, sofern der Buffer nicht bereits voll ist und dash<strong>in</strong>zufügende Objekt ke<strong>in</strong>e null Referenz ist:public void addElement (Object o) {/** Precondition !isFull(); o != null; **/buffer[<strong>in</strong> % buffer.length] = o;<strong>in</strong>++;/** Postcondition … **/}E<strong>in</strong>e denkbare Subklasse könnte nun mit null Referenzen umgehen, <strong>in</strong>dem es anstelle vonnull e<strong>in</strong> Defaultobjekt erzeugt und dem Buffer h<strong>in</strong>zufügt:public void addElement (Object o) {/** Precondition !isFull(); **/if (o==null)buffer[<strong>in</strong> % buffer.length] = new Default();elsebuffer[<strong>in</strong> % buffer.length] = o;<strong>in</strong>++;/** Postcondition … **/}Für die Spezialisierung gilt gemäss den Regeln für Ref<strong>in</strong>ement die verknüpfte Precondition(!isFull() AND o != null) OR !isFull(), die vere<strong>in</strong>facht werden kann zu !isFull().Matthias Hausherr Seite 7 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4. Erweiterte Assertion Support Implementationen4.1. Erläuterung zu den CodebeispielenIn diesem Kapitel werden zwei verschiedene DBC Implementationen für <strong>Java</strong> vorgestellt. Fürjede näher vorgestellte Implementation wird e<strong>in</strong> Codebeispiel mitgeliefert. Die Idee ist, e<strong>in</strong>ensimplen Buffer mit Pre- und Postconditions sowie e<strong>in</strong>em Invariant zu sichern und dem Lesere<strong>in</strong>en E<strong>in</strong>druck zu geben wie der Code aussieht. Die Codebeispiele basieren auf e<strong>in</strong>emBeispiel von der Jass Website.Die noch ungesicherte Klasse, von der jeweils ausgegangen wird, sieht wie folgt aus:package standardtest;public class Buffer {protected <strong>in</strong>t <strong>in</strong>, out;private Object[] buf;public Buffer (<strong>in</strong>t capacity) {// Preconditionbuf = new Object[capacity];// Postcondition}public boolean empty() {return <strong>in</strong> - out == 0;// Postcondition}public boolean full() {return <strong>in</strong> - out == buf.length;// Postcondition}public void add(Object o) {// Preconditionbuf[<strong>in</strong> % buf.length] = o;<strong>in</strong>++;// Postcondition}public Object remove() {// PreconditionObject o = buf[out % buf.length];out++;return o;// Postcondition}// Invariant}Buffer.javaLegende für alle Codebeispiele:// Precondition: Wird bei Methodene<strong>in</strong>tritt geprüft.// Postcondition: Wird bei Methodenaustritt geprüft.// Invariant: Wird vor und nach der Ausführung der Methode geprüft.Matthias Hausherr Seite 8 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.2. Erläuterung zu den Ref<strong>in</strong>ement CodebeispielenFür jede näher dargestellte Implementation wird zudem e<strong>in</strong> Beispiel e<strong>in</strong>es Ref<strong>in</strong>edBuffervorgestellt. Diese Subklasse erweitert die Klasse Buffer und erweitert die Basisklasse umfolgende drei Punkte:• Die Methode conta<strong>in</strong>s(Object o) prüft, ob e<strong>in</strong> Objekt bereits im Buffer vorhanden ist.• Die Methode add(Object o) soll neu null Parameter erlauben und damit diePrecondition der Basisklasse schwächen. Wird e<strong>in</strong> null Parameter detektiert wird mitnew Object() e<strong>in</strong> Object erzeugt und <strong>in</strong> den Buffer e<strong>in</strong>gefügt.• Die Postcondition der Methode add wird um e<strong>in</strong>e Prüfung erweitert und damitgestärkt. Diese prüft ob das Object tatsächlich e<strong>in</strong>gefügt wurde. Hierfür wird dieMethode conta<strong>in</strong>s(Object o) des Ref<strong>in</strong>edBuffer verwendet.Die noch ungesicherte Klasse, von der jeweils ausgegangen wird, sieht wie folgt aus:package ref<strong>in</strong>ementtest;public class Ref<strong>in</strong>edBuffer extends Buffer {public Ref<strong>in</strong>edBuffer(<strong>in</strong>t capacity) {super(capacity);}public void add(Object o) {// Preconditionif (o == null) {o = new Object();}super.add(o);// Postcondition}public boolean conta<strong>in</strong>s(Object o) {// Preconditionfor (<strong>in</strong>t i = 0; i < <strong>in</strong> % buf.length; i++) {if (buf[i].equals(o)) {return true;}}return false;}}Ref<strong>in</strong>edBuffer.javaLegende für alle Codebeispiele:// Precondition: Wird bei Methodene<strong>in</strong>tritt geprüft.// Postcondition: Wird bei Methodenaustritt geprüft.// Invariant: Wird vor und nach der Ausführung der Methode geprüft.Matthias Hausherr Seite 9 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.3. Jass4.3.1. FactsErster Release: 1999Aktuelle Version: 2.0.14Entwicklungsstatus: Production/StableNext Release Date: Jass 3.0 / Datum unbekanntKosten:FreewareWebsite:http://csd.<strong>in</strong>formatik.uni-oldenburg.de/~jass/4.3.2. BeschreibungJass benutzt für die Def<strong>in</strong>ition der DBC Elemente e<strong>in</strong>e eigene Inputsprache, die jedoch fürjeden <strong>Java</strong>entwickler leicht zu erlernen ist, da die Syntax simpel ist und die Anzahl derkeywords ger<strong>in</strong>g. An dieser Stelle sei darauf h<strong>in</strong>gewiesen, dass die kommende Jass Version3.0 über ke<strong>in</strong>e eigene Inputsprache mehr verfügen wird sondern JML hierfür verwendenwird.Um die eigene Inputsprache zu verarbeiten und <strong>in</strong> reguläre <strong>Java</strong> Befehle umzuwandeln,benutzt Jass e<strong>in</strong>en Precompiler der komplett <strong>in</strong> <strong>Java</strong> programmiert ist. Der Entwicklerergänzt se<strong>in</strong>en <strong>Java</strong>code mit Jass Input und stellt dem Precompiler e<strong>in</strong> File wie z.B.sample.jass zur Verfügung. Dabei muss der Programmierer Preconditions am Anfang derMethode und Postconditions am Schluss der Methode platzieren. Invariants werden amSchluss des Klassensources platziert. Nach dem Preprocessorstep liegt e<strong>in</strong> kompiliertessample.java File vor. Dieses kann wie gewohnt mit den üblichen <strong>Java</strong> Tools kompiliert undausgeführt werden.Das Kompilat des Precompilers ersetzt die Inputsprache durch verschiedene Elemente. FürInvariants wird zu Beg<strong>in</strong>n und beim Ende der Methode jeweils e<strong>in</strong> Aufruf der Jass MethodeJassCheckInvariant(Str<strong>in</strong>g errorLocation) e<strong>in</strong>gefügt und als Parameter e<strong>in</strong>eKurzbeschreibung mitgegeben, wo die Invariant Prüfung ausgelöst wurde. Diese Methodesowie weitere von Jass <strong>in</strong>tern benötigte Methoden stehen <strong>in</strong> e<strong>in</strong>em vom Precompilergenerierten Abschnitt am Schluss des Sourcecodes.Wird bei der Postcondition auf die sogenannte Old Variable zugegriffen, welche den Zustanddes Objektes bei Methodene<strong>in</strong>tritt speichert, wird zu Beg<strong>in</strong>n der Methode das Objekt cloned.Aus diesem Grund müssen Klassen, deren Postconditions auf die Variable Old zugreifen,auch das Interface cloneable implementieren. Es müssen dabei nur jene Variablen effektivkopiert werden, die auch tatsächlich mit Old referenziert werden.Die Pre- bzw. Postconditions werden vom Precompiler <strong>in</strong> if Statements umgewandelt, diesofern sie false returnen, Exceptions werfen. Namentlich handelt es sich um die(jass.runtime.) PreconditionException, PostconditionException und die InvariantException.Bei ihrer Erzeugung per Konstruktor wird der Auftretensort des Fehlers sowie e<strong>in</strong>e kurzeFehlermeldung mitgegeben. Zusätzlich ist es möglich, Conditions mit e<strong>in</strong>em Label zuversehen, das beim Werfen der Exception angezeigt wird.Bei der Def<strong>in</strong>ition von Preconditions dürfen nur öffentlich e<strong>in</strong>sehbare Variablen undMethoden verwendet werden. Dies entspricht der availability Regel, die Bertrand Meyere<strong>in</strong>geführt hat und es dem Client der Klasse erleichtern soll zu verstehen, unter welchenBed<strong>in</strong>gungen die Methode aufgerufen werden kann.Auf der Jass Website gibt es viele kle<strong>in</strong>e Beispiele und Tutorials. E<strong>in</strong>e ausführlicheDokumentation gibt es nicht. Die von Jass mitgelieferten Beispiele s<strong>in</strong>d ansehnlich underleichtern den E<strong>in</strong>stieg, gehen aber nicht über e<strong>in</strong>fache Examples h<strong>in</strong>aus.Matthias Hausherr Seite 10 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.3.3. Syntaktische ElementeIn diesem Abschnitt werden verschiedene syntaktische Elemente der Jass Inputsprache kurzerklärt mit dem Ziel, dem Leser die Arbeit mit Jass näherzubr<strong>in</strong>gen. Die Codebeispiele <strong>in</strong>diesem Abschnitt stammen von der offiziellen Jass Website.Für präzisere Beschreibungen der Inputsprache und dessen Anwendung möge sich dergeneigte Leser auf der offiziellen Jass Website <strong>in</strong>formieren.requirePreconditions müssen am Beg<strong>in</strong>n e<strong>in</strong>er Methode platziert werden und werden durch daskeyword require gekennzeichnet. Require Statements prüfen die angegebenen Conditionsund werfen e<strong>in</strong>e entsprechende Exception, falls diese nicht e<strong>in</strong>gehalten werden.public void addElement (Object o) {/** require !isFull(); o != null; **/...}ensurePostconditions müssen am Schluss e<strong>in</strong>er Methode platziert und durch das keyword ensuregekennzeichnet werden. Ensure ist identisch zu require, ausser dass es Post- und nichtPreconditions kennzeichnet. In e<strong>in</strong>er Postcondition kann mit dem keyword Result auf denReturnwert der Methode zugegriffen werden.public void addElement (Object o) {.../** ensure !isEmpty() && conta<strong>in</strong>s(o); **/}OldMit der speziellen Variable Old kann auf den Zustand des Objektes vor Methodenausführungzugegriffen werden. Um auf Old zugreifen zu können, muss die Klasse der Postconditionzw<strong>in</strong>gend das Interface Cloneable implementieren. Es müssen dabei nur jene Variableneffektiv kopiert werden, die auch tatsächlich mit Old referenziert werden.public void addElement (Object o) {.../** ensure !isEmpty() && conta<strong>in</strong>s(o); count == Old.count+1; **/}changeonlyMit dem Konstrukt changeonly{…} können Attribute spezifiziert werden, die sich veränderthaben dürfen. Attribute, die nicht <strong>in</strong> changeonly aufgelistet s<strong>in</strong>d, dürfen ke<strong>in</strong>en verändertenWert aufweisen. E<strong>in</strong> changeonly mit e<strong>in</strong>er leeren Liste steht entsprechend dafür, dass ke<strong>in</strong>eder Variablen ihren Wert verändert haben darf. Damit lässt sich e<strong>in</strong>fach immutabilitysicherstellen analog den const Methoden aus C++. Für den Gebrauch dieses Konstruktesmuss das Interface Cloneable <strong>in</strong> der Klasse der Postcondition implementiert werden.public void addElement (Object o) {.../** ensure !isEmpty() && conta<strong>in</strong>s(o); Old.count == count-1;changeonly{count,buffer}; **/}Matthias Hausherr Seite 11 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong><strong>in</strong>variantE<strong>in</strong> Invariant muss am Ende der Klasse spezifiziert werden und wird durch das keyword<strong>in</strong>variant gekennzeichnet.public class Buffer {.../** <strong>in</strong>variant 0


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>forall und existsMit den Ausdrücken forall und exists können Conditions überprüft werden, die auf e<strong>in</strong>ebestimmte Menge von Objekten zutreffen müssen.(forall i : {out%buf.length .. <strong>in</strong>%buf.length-1} # buf[i] != null);4.3.4. <strong>Java</strong>Doc ErweiterungE<strong>in</strong> Highlight von Jass besteht <strong>in</strong> der Erweiterung von <strong>Java</strong>Doc durch eigene Tags. Wie vonDBC verlangt ist es mit Jass möglich, direkt aus den jass Files e<strong>in</strong>e <strong>Java</strong>Doc zu erstellen, diemit DBC Informationen angereichert ist.Für die Methoden add und remove des Beispiels im Abschnitt Codebeispiel sieht dasErgebnis (die Methodenbeschreibungen ausgenommen) wie folgt aus:4.3.5. Ref<strong>in</strong>ementJass überlässt dem Entwickler die Entscheidung, ob er die Vererbungsregeln für <strong>Contract</strong>se<strong>in</strong>halten möchte. Falls er dies tut so muss er <strong>in</strong> der Subklasse das Interfacejass.runtime.Ref<strong>in</strong>ement implementieren. Das Interface selber hat ke<strong>in</strong>e Methoden sondernlöst zur Runtime Überprüfungen aus, die im Falle e<strong>in</strong>es Regelbruches e<strong>in</strong>ejass.runtime.Ref<strong>in</strong>ementExecption werfen. E<strong>in</strong>e solche Exception bedeutet im Klartext, dassetwas mit dem <strong>Design</strong> nicht <strong>in</strong> Ordnung ist.Leider musste ich feststellen, dass der eben beschriebene Mechanismus nur mangelhaftimplementiert wurde. <strong>Design</strong>fehler bei der Def<strong>in</strong>ition der Conditions werfen nur dannRef<strong>in</strong>ementExceptions, falls diese zur Runtime e<strong>in</strong>en E<strong>in</strong>fluss haben. E<strong>in</strong>e <strong>in</strong> der Subklasseverstärkte Precondition wird zum Beispiel nur entdeckt, falls diese nicht erfüllt wird und somitden Methodenaufruf verh<strong>in</strong>dert. Analog dazu ist es ist zum Beispiel möglich e<strong>in</strong>ePostcondition zu entfernen, während sie <strong>in</strong> der Basisklasse vorhanden ist, und dieRef<strong>in</strong>ementchecks weisen den Entwickler unter Umständen nicht darauf h<strong>in</strong>.Für die die Prüfung, ob die Regeln der <strong>Contract</strong> Inheritance e<strong>in</strong>gehalten werden verwendetJass e<strong>in</strong>e sogenannte Abstraction Function. Diese projeziert e<strong>in</strong>en konkreten Zustand derSubklasse auf e<strong>in</strong> Objekt ihrer Superklasse. Die Abstraction Function muss <strong>in</strong> Form derMethode jassGetSuperState def<strong>in</strong>iert werden, die e<strong>in</strong>e Referenz auf e<strong>in</strong> Objekt des Typender Basisklasse zurückgibt. Dieses Objekt muss sich im selben Zustand bef<strong>in</strong>den wie auchdas Objekt des Typs Subklasse. Für e<strong>in</strong>en Buffer bedeutet dies z.B. dass das Objekt derBasisklasse dieselben Elemente hat wie das Objekt der Subklasse. In e<strong>in</strong>igen Fällen ist dieAbstraction Function trivial (siehe Ref<strong>in</strong>ement Codebeispiel), <strong>in</strong> anderen Fällen kann dieMatthias Hausherr Seite 13 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>Suche e<strong>in</strong>er Abstraction Function e<strong>in</strong> ziemlich mühsamer und zeitraubender Prozess se<strong>in</strong>.Auch die Tatsache, dass Conditions teilweise redundant <strong>in</strong> Basis- und Subklasseimplementiert se<strong>in</strong> müssen h<strong>in</strong>terlässt e<strong>in</strong>en zwiespältigen E<strong>in</strong>druck.4.3.6. Codebeispielpackage standardtest;public class Buffer implements Cloneable {protected <strong>in</strong>t <strong>in</strong>, out;private Object[] buf;public Buffer() {buf = new Object[0];/** ensure buf.length == 0; **/}public Buffer (<strong>in</strong>t capacity) {buf = new Object[capacity];/** ensure buf.length == capacity; **/}public boolean empty() {return <strong>in</strong> - out == 0;/** ensure changeonly{}; **/}public boolean full() {return <strong>in</strong> - out == buf.length;/** ensure changeonly{}; **/}public void add(Object o) {/** require [buffer_not_full] !full(); [valid_object] o != null; **/buf[<strong>in</strong> % buf.length] = o;<strong>in</strong>++;/** ensure changeonly{<strong>in</strong>,buf}; Old.<strong>in</strong> == <strong>in</strong> - 1; **/}public Object remove() {/** require [buffer_not_empty] !empty(); **/Object o = buf[out % buf.length];out++;return o;/** ensure changeonly{out}; Old.out == out - 1;[valid_object] Result != null; **/}protected Object clone() {Object b = null; // This is sufficient because Oldtry { // only accesses the members <strong>in</strong> and outb = super.clone();} catch (CloneNotSupportedException e){}return b;}/** <strong>in</strong>variant [range] 0


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.3.7. Ref<strong>in</strong>ement Codebeispielpackage ref<strong>in</strong>ementtest2;public class Ref<strong>in</strong>edBuffer extends Bufferimplements jass.runtime.Ref<strong>in</strong>ement {public Ref<strong>in</strong>edBuffer(<strong>in</strong>t capacity) {super(capacity);/** ensure buf.length == capacity; **/}public void add(Object o) {/** require [buffer_not_full] !full(); **/if (o == null) {o = new Object();}super.add(o);/** ensure changeonly{<strong>in</strong>,buf}; Old.<strong>in</strong> == <strong>in</strong> - 1;[conta<strong>in</strong>s_object] conta<strong>in</strong>s(o); **/}public boolean conta<strong>in</strong>s(Object o) {/** require [Valid_object] o != null; **/for (<strong>in</strong>t i = 0; i < <strong>in</strong> % buf.length; i++) {if (buf[i].equals(o)) {return true;}}return false;/** ensure changeonly{}; **/}// Abstraction Functionprivate Buffer jassGetSuperState() {return (Buffer) this;}/** <strong>in</strong>variant [range] 0


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.4. C4J4.4.1. FactsErster Release: UnbekanntAktuelle Version: 2.5.2.Entwicklungsstatus: Production/StableNext Release: C4J 3 RC 1 / Dezember 06Kosten:FreewareWebsite:http://c4j.sourceforge.net/4.4.2. BeschreibungC4J sieht vor, dass für jedes <strong>Java</strong> File, das gesichert werden soll, e<strong>in</strong> separates <strong>Java</strong> Fileprogrammiert wird, das den zum File zugehörigen <strong>Contract</strong> implementiert. Der <strong>Contract</strong> wirdzur Kompilierzeit mittels e<strong>in</strong>er Annotation im <strong>Java</strong> Source File mit dem <strong>Contract</strong> Fileverknüpft. Das Resultat ist e<strong>in</strong>e saubere Trennung von Sourcecode und <strong>Contract</strong>. Der<strong>Contract</strong> selber wird <strong>in</strong> <strong>Java</strong> implementiert.Die Verknüpfung von Source und <strong>Contract</strong> File wird mit dem <strong>in</strong> JDK 5.0 e<strong>in</strong>geführtenjavaagent implementiert. Diese erlaubt es zur Runtime die Verträge an die Source zu l<strong>in</strong>ken,<strong>in</strong>dem der Agent den Ladeprozess e<strong>in</strong>er Klasse beobachtet und Methodenaufrufe <strong>in</strong> dieagent library auslöst, die den <strong>By</strong>tecode verändern. C4J be<strong>in</strong>haltet e<strong>in</strong>e sogenannteInstrumentor Klasse, die den <strong>By</strong>tecode aller Sources verändert (sogenannt <strong>in</strong>strumentiert),die über e<strong>in</strong>e <strong>Contract</strong>Reference Annotation mit e<strong>in</strong>em Vertrag verknüpft s<strong>in</strong>d.Für jede Methode lassen sich im <strong>Contract</strong> File zwei Methoden schreiben, die jeweils die Preunddie Postcondition darstellen. Der Invariant wird <strong>in</strong> der speziellen Methode ClassInvariantimplementiert. Innerhalb dieser Methoden können Conditions mit assert Statements geprüftwerden. Diese Methoden werden zu den für Pre- und Postconditions bzw. Invariantsüblichen Stellen zur Runtime aufgerufen. Wird e<strong>in</strong> <strong>Contract</strong> nicht e<strong>in</strong>gehalten, resultiert e<strong>in</strong>java.lang.AssertionError.<strong>Contract</strong> Implementationen haben e<strong>in</strong>e Referenz auf das Objekt, das sie verifizieren. Diesermöglicht bequemen Zugriff auf Variablen und Methoden des Objekts. Um die availabilityRegel von Bertrand Meyer nicht zu verletzen, darf bei der Def<strong>in</strong>ition von Preconditionsjedoch ausschliesslich auf öffentlich sichtbare Elemente zugegriffen werden.C4J arbeitet für die Prüfung der e<strong>in</strong>zelnen Conditions mit <strong>Java</strong> Assertions, die erst seit JDK1.4 verfügbar und per default deaktiviert s<strong>in</strong>d. Aus diesem Grund muss das Programm, dasDBC mit C4J implementiert, auch mit dem tag –enableassertions gestartet werden.E<strong>in</strong>e Schwachstelle von C4J ist das Fehlen e<strong>in</strong>er e<strong>in</strong>fachen Möglichkeit des Zugriffs auf denObjektzustand vor Methodenausführung <strong>in</strong>nerhalb von Postconditions. Während Jass hierfürbequeme Konstrukte bietet, ist dies <strong>in</strong> C4J nur relativ umständlich möglich. Besserung fürdieses Problem verspricht der nächste C4J Release, die Version 3.0. Diese wird es demEntwickler erlauben mit den keywords old und current auf den früheren respektive denaktuellen Inhalt der Variable zuzugreifen.Leider gibt es ke<strong>in</strong>e ausführliche Dokumentation und die C4J Website bietet nure<strong>in</strong>geschränkte Tutorials und Erläuterungen. Die mitgelieferten Examples s<strong>in</strong>d kaumbrauchbar. C4J ist e<strong>in</strong>fach zu lernen und die E<strong>in</strong>arbeitungszeit ger<strong>in</strong>g. Es gibt nur wenigegewöhnungsbedürftige Konstrukte und auch diese s<strong>in</strong>d schnell begriffen.Matthias Hausherr Seite 16 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.4.3. Framework ElementeDer <strong>Contract</strong> kann, sofern er e<strong>in</strong>e Erweiterung der Klasse <strong>Contract</strong>Base darstellt und imKonstruktor die target Referenz an super übergibt mit der Referenz m_target, auf dieVariablen und Methoden des zu verifizierenden Objekts zugreifen.Möchte man den Zustand e<strong>in</strong>es Objektes vor Methodenausführung <strong>in</strong> e<strong>in</strong>er Postconditionprüfen, so muss dieser Wert <strong>in</strong>nerhalb e<strong>in</strong>er Precondition mit e<strong>in</strong>em Aufruf der MethodesetPreconditionValue(„key“, m_target.myVariable) gespeichert werden. Die mit dieserMethode gespeicherten Objekte müssen Cloneable nicht zw<strong>in</strong>gend implementieren. Es wirdlediglich die Referenz auf das Objekt abgespeichert, ke<strong>in</strong>e Kopie des Objektes. Um auf dieVariablenwerte vor Methodenausführung zugreifen zu können, muss man deshalb manuelle<strong>in</strong>e Kopie des Elementes erzeugen und mit setPreconditionValue abspeichern. PrimitiveDatentypen können ohne die Erstellung e<strong>in</strong>er solchen Kopie direkt gespeichert werden, dadiese ke<strong>in</strong>e Objekte darstellen und deshalb wie <strong>in</strong> <strong>Java</strong> üblich automatisch kopiert werden.Das Objekt kann anschliessend <strong>in</strong> der Postcondition mit e<strong>in</strong>em Aufruf der MethodegetPreconditionValue(„key“) abgefragt und für Conditions benutzt werden.Mit der Methode getTargetField(„key“) kann auf private Variablen des zu prüfenden Objekteszugegriffen werden.Diese Framework Elemente s<strong>in</strong>d ziemlich umständlich und werden im C4J ReleaseCandidate 3.0 durch e<strong>in</strong>fachere Konstrukte ersetzt.4.4.4. Ref<strong>in</strong>ementIm Gegensatz zu Jass setzt C4J die Ref<strong>in</strong>ement Regeln konsequent um. Verträge werdenan ihre Subklassen mitvererbt und s<strong>in</strong>d an diese gebunden. E<strong>in</strong>e Subklasse kann zusätzlichan e<strong>in</strong>en eigenen <strong>Contract</strong> gebunden werden. In solch e<strong>in</strong>em Fall wird zuerst diePrecondition der Basisklasse geprüft und anschliessend die der Subklasse. NachMethodenausführung wird zuerst die Postcondition der Subklasse geprüft und dann die derBasisklasse. Bei den Invariants wird immer zuerst der Invariant der Basisklasse und dannjener der Subklasse ausgeführt.Bei der Erarbeitung des Ref<strong>in</strong>ement Codebeispiels b<strong>in</strong> ich auf e<strong>in</strong>en merkwürdigen Fehlergestossen. E<strong>in</strong>e Postcondition e<strong>in</strong>er Subklasse, deren Methode e<strong>in</strong>en supercall be<strong>in</strong>haltete,warf Exceptions, obwohl diese zweifelsfrei richtig implementiert wurde. Nach Recherche desProblems im C4J Forum stellte sich heraus, dass es sich hierbei um e<strong>in</strong>en Bug handelte. Füre<strong>in</strong>e Beschreibung des Bugs und e<strong>in</strong>en Workaround siehe Quellenangaben.Leider war es mir entgegen me<strong>in</strong>en Erwartungen nicht möglich, e<strong>in</strong>e Precondition <strong>in</strong> e<strong>in</strong>erSubklasse zu schwächen. C4J prüft <strong>in</strong> jedem Fall zur Runtime zuerst die Precondition derBasisklasse zuerst und anschliessend die der Subklasse. Dies führt aufgrund der strengerenConditions der Basisklasse zu e<strong>in</strong>em Fehler.Der Grund dafür ist, dass C4J bei der Prüfung der Conditions nicht die üblichen Ref<strong>in</strong>ementRegeln verwendet, sondern e<strong>in</strong>en eigenen Weg geht, der <strong>in</strong> e<strong>in</strong>er eigenen Reihenfolge der<strong>Contract</strong>verifizierung mündet. Als Konsequenz muss <strong>in</strong> jedem Fall sowohl der <strong>Contract</strong> derBasisklasse als auch jener der Subklasse e<strong>in</strong>gehalten werden.Dieses Verhalten kann <strong>in</strong> Szenarien <strong>in</strong> denen e<strong>in</strong>e Klasse mehrere Interfaces implementiert,die jeweils dieselbe Methode mit unterschiedlicher Precondition def<strong>in</strong>ieren, Vorteileaufweisen. In e<strong>in</strong>em solchen Fall kann e<strong>in</strong>e OR Verknüpfung der Preconditions unterUmständen nicht ausreichend se<strong>in</strong> und zu irrtümlicherweise erfüllten Preconditions führen.Matthias Hausherr Seite 17 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>Die Ause<strong>in</strong>andersetzung mit diesem Mechanismus ist wichtig, möchte man C4J <strong>in</strong> e<strong>in</strong>emgrösseren Projekt nutzen. Leider ist dieses Verhalten nur mangelhaft dokumentiert. Diebeste verfügbare Quelle zu diesem Thema besteht <strong>in</strong> e<strong>in</strong>em Forumthread des offiziellenForums. Für mehr Informationen über dieses Thema ist der L<strong>in</strong>k <strong>in</strong> den Quellenangaben zukonsultieren.Um e<strong>in</strong> Verständnis für den Ref<strong>in</strong>ement Mechanismus von C4J zu entwickeln, muss mansich zuerst mit der Materie ause<strong>in</strong>andersetzen. Grundsätzlich ist das Ref<strong>in</strong>ement <strong>in</strong> C4J gutimplementiert: Conditions müssen nicht redundant <strong>in</strong> Basisklasse und Subklasseimplementiert werden so wie dies z.B. bei Jass der Fall ist. Da für jedes Source File e<strong>in</strong><strong>Contract</strong> File besteht, geht die Übersicht auch bei komplexeren Sourcestrukturen nichtverloren.4.4.5. Codebeispielpackage standardtest;import net.sourceforge.c4j.<strong>Contract</strong>Reference;@<strong>Contract</strong>Reference(contractClassName = "standardtest.Buffer<strong>Contract</strong>")public class Buffer {// Klassencode ...}Buffer.javapackage ref<strong>in</strong>ementtest2;import net.sourceforge.c4j.<strong>Contract</strong>Base;public class Buffer<strong>Contract</strong> extends <strong>Contract</strong>Base {public Buffer<strong>Contract</strong>(Buffer target) {super(target);}public void pre_Buffer(<strong>in</strong>t capacity) {assert capacity > 0;}public void pre_add(Object o) {assert o != null;assert !m_target.full();for (<strong>in</strong>t i = 0; i < m_target.buf.length; i++) {if (m_target.buf[i] != null) {setPreconditionValue("<strong>in</strong>"+i, m_target.buf[i]);}}}setPreconditionValue("<strong>in</strong>", m_target.<strong>in</strong>);Matthias Hausherr Seite 18 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>public void post_add(Object o) {<strong>in</strong>t bufLen = m_target.buf.length;for (<strong>in</strong>t i = 0; i < bufLen; i++) {if (m_target.buf[i] != null && i != m_target.<strong>in</strong>-1 % bufLen) {Object preIn = ((Object) getPreconditionValue("<strong>in</strong>"+i));assert preIn.equals(m_target.buf[i]);}}assert m_target.buf[m_target.<strong>in</strong>-1 % bufLen].equals(o);}<strong>in</strong>t preIn = ((Integer) getPreconditionValue("<strong>in</strong>"));assert preIn == m_target.<strong>in</strong> - 1;public void pre_remove() {assert !m_target.empty();setPreconditionValue("out", m_target.out);}public void post_remove() {<strong>in</strong>t preOut = ((Integer) getPreconditionValue("out"));assert preOut == m_target.out - 1;assert getReturnValue() != null;}public void classInvariant() {assert 0


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>4.4.6. Ref<strong>in</strong>ement Codebeispielpackage ref<strong>in</strong>ementtest2;import net.sourceforge.c4j.<strong>Contract</strong>Reference;@<strong>Contract</strong>Reference(contractClassName ="ref<strong>in</strong>ementtest2.Ref<strong>in</strong>edBuffer<strong>Contract</strong>")public class Ref<strong>in</strong>edBuffer extends Buffer {// Klassencode ...}Ref<strong>in</strong>edBuffer.javapackage ref<strong>in</strong>ementtest2;public class Ref<strong>in</strong>edBuffer<strong>Contract</strong> {private Ref<strong>in</strong>edBuffer target = null;public Ref<strong>in</strong>edBuffer<strong>Contract</strong>(Ref<strong>in</strong>edBuffer target) {this.target = target;}public void pre_add(Object o) {// Abschwächen der Precondition nicht möglich! Die// Precondition der Basisklasse bleibt <strong>in</strong> jedem Fall// bestehen und wird vor Aufruf dieser Methode ausgeführt.// Siehe Kapitel C4J >> Ref<strong>in</strong>ement für mehr Information.}public void post_add(Object o) {assert target.conta<strong>in</strong>s(o);}public void pre_conta<strong>in</strong>s(Object o) {assert o != null;}}Ref<strong>in</strong>edBuffer<strong>Contract</strong>.javaMatthias Hausherr Seite 20 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>5. EmpfehlungSowohl Jass als auch C4J weisen völlig verschiedene Implementationsansätze auf. C4Jvermag mich mehr zu überzeugen als Jass. Besonders die strikte Trennung von Source und<strong>Contract</strong> erweist sich als elegante Lösung. Die Schwächen wie die teilweise umständlichenKonstrukte von C4J, werden vorraussichtlich mit dem nächsten Release Candidate von C4Jaddressiert und verbessert.Das etwas gewöhnungsbedürftige Ref<strong>in</strong>ement und die mangelnde Dokumentation s<strong>in</strong>dSchwachstellen. Wer sich überlegt C4J für grössere Projekte e<strong>in</strong>zusetzen, soll sich zuerstvertieft mit dem Ref<strong>in</strong>ement Verhalten von C4J ause<strong>in</strong>andersetzen um das nötigeGrundwissen zu erarbeiten.Matthias Hausherr Seite 21 / 22


<strong>Design</strong> <strong>By</strong> <strong>Contract</strong> <strong>in</strong> <strong>Java</strong>6. Quellenangaben<strong>Design</strong> <strong>By</strong> <strong>Contract</strong>E<strong>in</strong>führung zu DBC von Eiffel Softwarehttp://archive.eiffel.com/doc/manuals/technology/contract/Prof. Bertrand Meyers ETH Homepagehttp://se.ethz.ch/~meyer/Verschiedene Wikipedia Artikelhttp://en.wikipedia.org/wiki/<strong>Design</strong>_by_contracthttp://de.wikipedia.org/wiki/<strong>Design</strong>_<strong>By</strong>_<strong>Contract</strong>http://en.wikipedia.org/wiki/Bertrand_MeyerDer DBC ‘Request For Enhancement’ – ‘Support For <strong>Design</strong> by <strong>Contract</strong>' auf bugs.sun.comhttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4449383<strong>Java</strong> AssertionsBehandlung der Themen Assertions und Exceptionshttp://www.javaforce.com/content/view/119/66/http://leepo<strong>in</strong>t.net/notes-java/flow/assertions/assertions.htmlJassJass Website und Quelle für Codebeispielehttp://csd.<strong>in</strong>formatik.uni-oldenburg.de/~jass/C4JC4J Homepagehttp://c4j.sourceforge.net/Erläuterungen zum <strong>Java</strong> Agent welcher von C4J verwendet wirdhttp://javahowto.blogspot.com/2006/07/javaagent-option.htmlhttp://www.javalobby.org/java/forums/t19309.htmlBugreport und Workaround sowie Information zu der Abarbeitungsreihenfolge der Conditionshttp://sourceforge.net/forum/forum.php?thread_id=1607817&forum_id=547819Matthias Hausherr Seite 22 / 22

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!