Software Engineering: Using Annotation in Object Oriented Programming
Software Engineering: Using Annotation in Object Oriented Programming
Software Engineering: Using Annotation in Object Oriented Programming
Lectures 1-2:
Using Annotation in
Object Oriented Programming
Outline
●
Liskov and Guttag (2000), Chapters 2-3,5,9
●
Java language specification (annotation
feature)
●
Recent paper on annotation-based design
languages:
– Duc et al. (2018)
CustomerSimple
- id : int
- name : String
+ setName(String)
+ getId(): int
+ getName(): String
●
Using validation methods:
– rules are implicit (implied by the method behaviour)
– rules can not be applied at compile time (because
method execution is required)
●
Using annotation:
– Java: annotation; C#: attribute
– rules are explicit in the design
– rules can be applied at compile time
●
to validate the design
– define behaviour of validation methods
Duc M. L. Software Engineering 10
Example: validate id method
●
id value is checked in the constructor
public class CustomerSimple {
private int id;
private String name;
@SuppressWarnings("unchecked") Provided by
void myMethod() { } Java
@Author(name = "Jane Doe")
class MyClassA { }
Customer CustomerCtrl
Header spec.
Class
object
representation - attributeA : type
+ operationX()
operation spec.
DomainConstraint
type(): String (“null”)
is attached to mutable(): boolean (true)
Field optional(): boolean (true)
length(): int (-1)
min(): double (Double.NaN)
max(): double (Double.Nan)
@DomainConstraint{
type="String",
mutable=true,
optional=false,
length=50
}
@DOpt(type=Mutator) Customer
@DAttr(“name”)
- id : int
- name : String
@DOpt(type=Observer) + Customer(int, String)
@DAttr(“id”) + setName(String)
+ getId(): int
+ getName(): String
@DOpt(type=Observer) - validateId(int): boolean validation
@DAttr(“name”) - validateName(String): boolean methods
+ toString(): String
+ equals(Object): boolean
+ repOK(): boolean
@DOpt(type=MutatorAdd)
IntSet
- elements : Vector<Integer>
@DOpt(type=MutatorRemove) + IntSet()
+ insert(int)
@DOpt(type=ObserverContains) + remove(int)
+ isIn(int): boolean
+ choose(): int
@DOpt(type=ObserverSize) + size(): int
- getIndex(int): int
+ toString(): String
+ repOK(): boolean
/**
* @overview ...
* @attributes ...
* @object ...
* @abstract_properties ...
*/
class C
●
Name of the concept that we want to model as
class
Customer IntSet
/**
* @overview IntSet are mutable, unbounded sets
* of integers.
*/
public class IntSet
Duc M. L. Software Engineering 27
Example: Customer
Customers are people or
organisations with which
we have relationships.
Customer
/**
* @overview Customers are people or
* organisations with which we have
* relationships.
*/
public class Customer
Duc M. L. Software Engineering 28
Example: Integer
Integers are immutable
whole numbers (incl. 0)
and their negatives.
Integer
/**
* @overview Integers are immutable whole
* numbers (incl. 0) and their negatives.
*/
public class Integer
Duc M. L. Software Engineering 29
Specify the attributes
●
Written using tag @attributes
●
Each attribute entry has three parts:
●
name: the attribute name
●
(formal) type: the abstract data type of the attribute
●
concrete type: the actual data type
– left blank for now (added later)
●
Drawn in the second compartment of the UML
diagram
●
visibility (+/-) is not yet determined (added later)
IntSet
/**
* @overview ... as before ...
* @attributes
* elements Set<Integer>
*/
public class IntSet
Duc M. L. Software Engineering 32
Example: Customer
Customer
/**
* @overview ... as before ...
* @attributes
* id Integer
* name String
*/
public class Customer
Duc M. L. Software Engineering 33
Specify the abstract object
●
An object created from typical values of the
attributes
●
If has only one attribute:
●
use a typical value of the attribute, e.g.:
– set-based type: {x1,...,xn}
– others: e.g. -2, -1, …
●
If has more than one attributes:
●
use the tuple notation, e.g.:
A typical Customer is <d, n> where id(d), name(n)
:Customer
id = d
name = n
/**
* @overview ... as before ...
* @attributes ... as before ...
* @object A typical Customer is c=<d,n>, where
* id(d), name(n).
*/
public class Customer
Duc M. L. Software Engineering 35
Example: IntSet
:IntSet
elements = {x1,...,xn}
/**
* @overview ... as before ...
* @attributes ... as before ...
* @object A typical IntSet object is
* c={x1,...,xn}, where x1,...,xn are elements
*/
public class IntSet
Duc M. L. Software Engineering 36
Example: Integer
:Integer
value = ...,-2,-1,0,1,2,3,...
/**
* @overview ... as before ...
* @attributes
* value Integer
* @object Typical integers are ...,-2,-1,0,1,...
*/
public class Integer
●
Written using the tag @abstract_properties
●
Two types:
●
domain constraint
●
others
id Integer N N - 1 -
name String Y N 50 - -
elements Set<Integer> Y N - - -
●
Properties other than those captured in the
domain constraint
●
Specific to each abstract concept
●
Examples:
●
Set: elements are distinct
●
Array: elements form a sequence
/**
* @overview ... as before ...
* @attributes ... as before ...
* @object ... as before ...
* @abstract_properties
* mutable(elements)=true /\
* optional(elements)=false /\
* elements != {} →
* (for all x in elements. x is integer) /\
* elements != {} →
* (for all x, y in elements. x != y)
*/
public class IntSet
●
Wrapper types
●
Dynamic array
●
Wrapper class
●
An object data type that 'wraps' the primitive types
●
Suitable for used as formal attribute type
●
Auto-boxing: automatically converts ('wraps)
primitive values into wrapper objects
●
Auto-unboxing: the reverse, i.e. wrapper object →
primitive value
int Integer
long Long
float Float
double Double
char Character
Duc M. L. Software Engineering 49
/**
* @overview A program that creates and
* manipulates Integer objects. E.g.: Integer
*/
public class IntegerWrapper {
/**
* The run method
*/
public static void main(String[] args) {
Integer i;
int j, k;
// create object using auto-boxing
i = 5; /* i = Integer(5) */
import java.util.Vector;
...
Vector v1 = new Vector();
Vector<Integer> v = new Vector<>();
v
empty (size=0)
initial capacity
Duc M. L. Software Engineering 53
add()
v.add(1);
v.add(1); v 1 1 2 3 5
v.add(2);
v.add(3);
v.add(5);
int i = v.get(0);
auto-unboxing
i 1 v 1 1 2 3 5
v.set (0,-1);
v -1 1 2 3 5
v.remove(0);
v -1 1 2 3 5
1 2 3 5
int sz = v.size();
sz 4 v 1 2 3 5
●
Similarity:
●
a collection of items
●
items can be of different types
●
Differences:
●
Vector allows duplicates
●
Vector's elements can be accessed by index
IntSet
elements : Vector<Integer>
/**
* @overview ...
* @attributes
* elements Set<Integer> Vector<Integer>
* ...
*/
public class IntSet
Duc M. L. Software Engineering 60
Example: Customer
Customer
id : int
name : String
/**
* @overview ...
* @attributes
* id Integer int
* name String
* ...
*/
public class Customer
Duc M. L. Software Engineering 61
Guidelines for choosing concrete type
●
Must be supported by the prog. language
●
May be the same or different from the formal type
●
To balance between productivity and efficiency:
●
productivity: ease coding with the type
●
efficiency: run-time efficiency of the using code
(code that uses the type)
●
Customer:
●
attributes: id (int) and name (String)
represent
●
Customer objects <1,”Duc”>, <2,”Thang”>, ...
●
IntSet:
●
attribute: elements (Vector)
represents
●
IntSet objects {-11,2,3}, {10,-12,15}, ...
●
For each attribute, define an instance variable:
●
identifier = attribute name
●
data type = concrete type
●
access modifier: private
●
Modifier private is to protect attributes from
direct outside access:
●
recall: information hiding
Customer
- id : int
- name : String /**
* @overview ...
* @attributes
* id Integer int
* name String
* ...
*/
public class Customer {
private int id;
private String name;
}
/**
* @overview ...
* @attributes
* elements Set<Integer> Vector<Integer>
* ...
*/
public class IntSet {
private Vector<Integer> elements;
}
Duc M. L. Software Engineering 69
Annotate instance variables with
domain constraints
●
Annotate each instance variable with annotation
@DomainConstraint
– realises the essential domain constraints discussed
earlier
●
All @DomainConstraint’s properties are given
default values:
– can be omitted if not specified
●
All annotations are located in the package
utils:
●
We will discuss other annotations later
Duc M. L. Software Engineering 70
Annotation @DomainConstraint
@DomainConstraint{
type="Integer",
mutable=false, Customer
optional=false,
- id : int
min=1
} - name : String
@DomainConstraint{
type="String",
mutable=true,
optional=false,
length=50
}
@DomainConstraint(type="String",mutable=true,
optional=false,length=50)
private String name;
}
Duc M. L. Software Engineering 73
Example: IntSet
@DomainConstraint{
type="Vector",
mutable=true, IntSet
optional=false
- elements : Vector<Integer>
}
Customer
@DOpt(type=Mutator)
- id : int
- name : String
@DOpt(type=Observer) + Customer(int, String)
+ setName(String)
+ getId(): int
+ getName(): String
@DOpt(type=Observer)
- validateId(int): boolean
- validateName(String): boolean
@DOpt(type=Helper) + toString(): String
+ equals(Object): boolean
+ repOK(): boolean
@DOpt(type=Default)
Duc M. L. Software Engineering 77
Example: IntSet
@DOpt(type=
OptType.Constructor) (not needed)
IntSet
@DOpt(type=MutatorAdd)
- elements : Vector<Integer>
@DOpt(type=MutatorRemove) + IntSet()
+ insert(int)
@DOpt(type=ObserverContains) + remove(int)
+ isIn(int): boolean
+ choose(): int
@DOpt(type=ObserverSize) + size(): int
- getIndex(int): int
+ toString(): String
+ repOK(): boolean
●
@requires: pre-conditions
●
only required for partial procedures
●
@modifies: side-effects (if any)
●
list the parameter(s)
●
@effects: post-conditions
●
state the transformation of inputs into output
●
@pseudocode: the pseudocode (if any)
●
typically low level pseudocode statements
Duc M. L. PR2 84
Example: swap two numbers
/** detailed description
* Swap two numbers of behaviour
* @requires <tt>xy != null /\
* xy.length=2</tt>
* @modifies xy
* @effects <tt>xy = [xy_0[1],
* xy_0[0]]</tt>
*/
void swap(int[] xy)
Duc M. L. PR2 85
Specification language
●
A Java-like language that supports:
●
logical notation
●
reserved names (@requires, etc.) for the
specification components
Duc M. L. PR2 86
A Java-like language
●
Comments: single and block comments
●
Procedure definition
●
Java's primitive and array types
●
Keyword null
●
no semi-colon at end of statement
●
indentation, no curly brackets
Duc M. L. PR2 87
Statements & operators
●
Basic statements:
●
Java's variable declaration and assignment
●
Java's conditional and loop
●
read: read some data from some input
●
print: display some data to the standard output
●
return: return some data as output
●
High-level (natural language) statements are
also allowed
●
Operators:
●
eq (==), not eq (!=), lt (<), gt (>), etc.
Duc M. L. PR2 88
Operations on array
●
add x to a:
●
add x to the next index position in a
●
put x in a:
●
put x in any index in array a
●
delete x in a:
●
set the first item matching x in a to a pre-defined
constant used to denote the discarded state
Duc M. L. PR2 89
Logical notation
↔ <->
Duc M. L. PR2 90
Criteria of a good specification
●
Restrictive:
●
to rule out unsatisfactory implementations
●
include @requires when necessary
●
General:
●
to cover a majority of satisfactory implementations
●
use definitional-style description when necessary
●
Clear: balance between
●
conciseness: consolidate statements, use pseudocode
language syntax
●
redundancy: use example when necessary
Duc M. L. PR2 91
Example: swap
/**
* Swap two numbers
* @requires xy != null /\ xy.length=2
* @modifies xy
* @effects xy = [xy_0[1], xy_0[0]]
*/
void swap(int[] xy)
/** Redundancy
(use example)
* Swap two numbers
* @requires xy != null /\ xy.length=2
* @modifies xy
* @effects xy = [xy_0[1], xy_0[0]]
* e.g. xy=[1,2] /\ swap(xy)=[2,1]
*/
void swap(int[] xy)
Duc M. L. PR2 93
Operation specification guidelines (2)
●
Use a well-defined design specification
●
Scope is usually public (some are private)
●
Annotate with @DOpt, @AttrRef (where needed)
●
Must not use keyword static
●
Must take into account the attributes & abstract
properties
●
May use the _post postfix to denote value of a variable in
the post-condition
●
Can use keyword this to refer to other members
●
AttrRef is often (but not always) used with DOpt
●
DOpt is usually NOT required for constructor and
helper operations
●
AttrRef is usually NOT required for parameters
of non-constructor operations
●
Parameters:
●
one parameter for each non-optional, non-collection-
typed attribute
●
use @AttrRef to map each parameter to attribute
●
types must match the attributes' concrete types
●
@effects: if domain constraints apply then states
data validation for the arguments:
– throws NotPossibleException if violation occurs
/**
* @effects <pre>
* if custID, name are valid
* initialise this as <custID,name>
* else
* initialise this as <> and print error
* </pre>
*/
public Customer(@AttrRef("id") int custID,
@AttrRef("name") String name)
throws NotPossibleException
/**
* @effects <pre>
* if name is valid
* set this.name to name
* return true
* else
* return false</pre>
*/
@DOpt(type=OptType.Mutator) @AttrRef(”name”)
public boolean setName(String name)
/**
* @effects return <tt>id</tt>
*/
@DOpt(type=OptType.Observer) @AttrRef(”id”)
public int getId()
/**
* @effects return <tt>name</tt>
*/
@DOpt(type=OptType.Observer) @AttrRef(”name”)
public String getName()
@Override
public String toString()
●
No arguments
●
Returns a string representation of an object
●
similar to the abstract object definition
@Override
public boolean equals(Object o)
●
Takes an Object argument and returns
boolean
●
true if the argument is equal to the current object,
false if otherwise
●
Also means the two objects are behaviourally
equivalent
●
Generates a hash value from object state
●
For use as the storage key of an object in a
hash-based collection
– e.g. Hashtable, HashMap
●
Not discussed further
●
Operations that perform tasks needed by other
operations
●
Three common types of helper:
●
repOK: short for “representation OK”
●
Data validation
●
Utility
●
Check if the object state satisfies the abstract
properties
●
for testing the object and the overall implementation
●
Specified using the above:
●
scope: usually public (but can also be private)
Duc M. L. Software Engineering 112
Data validation
●
Validates input data against the domain
constraints
●
invoked by constructor, setter, and repOK
operations
●
Name: validateX, where X is an attribute name
(first letter capitalised)
●
Access modifier: private
●
Parameters: match the attribute
●
Return type: boolean
●
May also invoke other validate operations
Duc M. L. Software Engineering 113
/**
* @effects <pre> E.g: Customer
* if id is valid
* return true
* else
* return false
* </pre>
*/
private boolean validateId(int id)
/**
* @effects <pre>
* if name is valid
* return true
* else
* return false
* </pre>
*/
private boolean validateName(String name)
Duc M. L. Software Engineering 114
Utility
●
Other helper operations:
●
determined based on the specifications of the existing
operations
●
Examples:
●
IntSet.getIndex: needed by insert and remove
●
Rat.reduce: performs a key operation
●
Scope: (usually) private
●
made public if useful for outside access (e.g.
IntSet.isIn)
/**
* @effects <pre>
* if x is in this
* return the index where x appears
* else
* return -1</pre>
*/
private int getIndex(int x)
●
Collection class implements a marker interface
●
Essential constructor has empty parameter list
●
Essential mutators to maintain the collection
●
Essential observers to obtain information about
elements in the collection
/**
* @effects initialise <tt>this</tt> to be
* empty
*/
public IntSet()
/**
* @modifies <tt>this</tt>
* @effects <pre>
* if x already in this
* do nothing
* else
* add x to this, i.e., this_post=this+{x}</pre>
*/
@DOpt(type=OptType.MutatorAdd)
public void insert(int x)
/**
* @effects <pre>
* if x is in this
* return true
* else
* return false</pre>
*/
@DOpt(type=OptType.ObserverContains)
public boolean isIn(int x)
/**
* @effects return the cardinality of <prtt>this</tt>
*/
@DOpt(type=OptType.ObserverSize)
public int size()
/**
* @effects
* if this is not empty
* return Integer[] array of elements of this
* else
* return null
*/
@DOpt(type=OptType.Observer)
public Integer[] getElements()
●
Annotation is a feature of high-level OOPL (Java,
C#) that provides metadata for the code
– State-of-the-art Java tools make extensive use of
annotation
●
Conventional OOP design lacks support for
explicit design rules
●
Three annotations are introduced to define
essential design rules: @DOpt, @AttrRef,
@DomainConstraint
●
Collection classes need to additionally implement
a marker interface
Duc M. L. Software Engineering 129
Q&A