1. Aspect-Oriented
Programming and Design
For Java and AspectJ
Dean Wampler
Object Mentor, Inc.
dean@objectmentor.com
Friday, September 7, 2007 1
2. public class Account {
public Money getBalance()
{...}
public void credit(Money m)
{...}
public void debit(Money m)
{...}
...
}
Friday, September 7, 2007 2
3. For example...
public void credit(Money m) {
balance += m;
}
Friday, September 7, 2007 3
5. However,
Real applications need:
Transactions
public class BankAccount {
public Money getBalance(){...}
public void credit(Money m) {...}
Persistence
public void debit(Money m) {...}
...
}
Security
Friday, September 7, 2007 5
6. Back to our example...
public void credit(Money m) {
if (unauthorized())
throw new ...();
Money saveBalance = balance;
try {
beginTransaction();
balance += m;
persistBalance(balance);
} ...
Friday, September 7, 2007 6
12. Back to our example...
public void credit(Money m) {
balance += m;
}
Back to what we want...
Friday, September 7, 2007 12
13. Back to our example...
class-like declaration
public aspect PersistentAccount{
pointcut newBalance ( bind variables
Account a, Money newBal):
set (Money Account.balance) &&
args (newBal) && this (a);
remember “this”
... named set of “join points”
remember new value
any time “balance” is set
Friday, September 7, 2007 13
14. Back to our example...
“after advice”
... same arguments
after (
Account a, Money newBal) :
same
newBalance(a, newBal) {
pointcut
persist(a, newBal);
}
body of the advice
Friday, September 7, 2007 14
15. Types of advice
before
after returning
after throwing
after
around
Friday, September 7, 2007 15
16. Other terms
• Join point
• Pointcut
• Advice
• Cross-cutting concern
• Introduction (a.k.a. Inter-type declaration)
• Aspect
Friday, September 7, 2007 16
17. Pure Java AOP
Spring AOP
JBoss AOP
Friday, September 7, 2007 17
18. Spring AOP
@AspectJ Support
Friday, September 7, 2007 18
37. public interface Shape {
public double getArea();
public void draw();
}
Friday, September 7, 2007 37
38. public abstract class Polygon
implements Shape {
public Point getVertex(int index)
{...}
public void draw() {...}
public String toString() {...}
}
Friday, September 7, 2007 38
39. public class Square
extends Polygon {
public double getArea() {...}
}
public class Rectangle
extends Polygon {
public double getArea() {...}
}
Friday, September 7, 2007 39
40. Square is a Rectangle?
Isn’t it?
Friday, September 7, 2007 40
41. An Aspect Refactoring...
public interface Shape {
public double getArea();
public void draw();
}
Friday, September 7, 2007 41
42. public abstract class Polygon
implements Shape {
public Point getVertex(int index)
{...}
public void draw() {...}
public String toString() {...}
}
Friday, September 7, 2007 42
43. package shapes.tostring;
public aspect PolygonToString {
public String Polygon.toString()
{...}
}
Friday, September 7, 2007 43
44. package drawing;
public interface Drawable {
void draw();
}
Friday, September 7, 2007 44
46. #3
Liskov Substitution
Principle
Subtypes must be
substitutable for their
base types.
Friday, September 7, 2007 46
47. Square is a Rectangle?
What do the unit tests say?
Friday, September 7, 2007 47
48. public RectangleDrawTest {
extends ...
public void testDraw {
Shape[] shapes = new Shapes[] {
new Rectangle(...),
new Square(...)};
for (Shape s: shapes)
s.draw(); // just works...
}
}
Friday, September 7, 2007 48
49. Square is a Rectangle?
Apparently, it is!!
(at least in this context...)
Friday, September 7, 2007 49
51. Need to Change Polygon:
public abstract class Polygon
implements Shape {
public Point getVertex(int index)
{...}
List<Point> getVertices() {...}
}
Occasionally need to break OCP...
Package private!
Friday, September 7, 2007 51
52. package shapes; // same package
import ...;
aspect MutablePolygon {
public void
Polygon.setHeight(int i) {
List<Point> list = getVertices();
// Change appropriate points...
}
public void
Polygon.setWidth(int i) {...}
}
Friday, September 7, 2007 52
53. Square is a Rectangle?
Friday, September 7, 2007 53
54. public MutableRectangleTest ... {
public void testSetWidth{
Point p00, p20, p25, p05 = ...;
Rectangle rect =
new Rectangle(p00,p20,p25,p05);
(0,5) (2,5)
(0,0) (2,0)
Friday, September 7, 2007 54
55. public MutableRectangleTest ... {
public void testSetWidth{
Point p00, p20, p25, p05 = ...;
Rectangle r = new Rectangle
(p00,p20,p25,p05);
assertEquals(2, r.getWidth());
assertEquals(5, r.getHeight());
r.setWidth(3);
assertEquals(3, r.getWidth());
assertEquals(5, r.getHeight());
}
}
Friday, September 7, 2007 55
56. Square is a Rectangle?
Prove it! (or not...)
Friday, September 7, 2007 56
57. What if I Use a Square?
...
Rectangle r = new Square
(p00,p50,p55,p05);
assertEquals(5, r.getWidth());
assertEquals(5, r.getHeight());
r.setWidth(3);
assertEquals(3, r.getWidth());
assertEquals(5, r.getHeight());
This won’t pass!
Friday, September 7, 2007 57
58. Square is a Rectangle?
Not in
this context!!
Friday, September 7, 2007 58
59. LSP
Is
Context Dependent!
Friday, September 7, 2007 59
60. LSP Is the Basis for
Design by Contract
Friday, September 7, 2007 60
62. Contract4J: DbC for Java
annotation-based
@Contract
public abstract class Polygon
implements Shape {
@Pre(“index>=0”)
@Post(“$return != null”)
public Point getVertex(int index)
{...}
}
Friday, September 7, 2007 62
63. #5
Dependency
Inversion Principle
Abstractions should not depend upon
details.
Details should depend upon
abstractions.
Friday, September 7, 2007 63
64. Client Service
Client
Service Service
Friday, September 7, 2007 64
65. Service
Client
Service
«aspect»
«aspect»
Client
Client
ClientService
ClientService
Service Service
Friday, September 7, 2007 65
67. package shapes.tostring;
public aspect PolygonToString {
public String Polygon.toString()
{...}
} Do introductions violate OCP??
No
Friday, September 7, 2007 67
68. Open-Closed
Principle: Updated
A module should be open for
extension, but closed for source
and contract modification.
Friday, September 7, 2007 68
69. public aspect Tracer {
before(): call(* Polygon.*(..)) {
log(thisJoinPointStaticPart);
}
Similar!
}
public class LoggedPolygonDraws {
public void draw() {
log(“Polygon.draw”);
super.draw();
}
}
Friday, September 7, 2007 69
70. Liskov Substitution
Principle: Updated
Subtypes and aspects + base
types must be substitutable for
their base types.
Friday, September 7, 2007 70
71. public aspect PolygonMunger {
before(Polygon p): target(p) &&
call(* Polygon.draw(..)) {
p.addPoint(new Point(/*...*/));
}
}
Does this look safe??
Friday, September 7, 2007 71
72. Advice Substitution
Principle
Advice must obey the contract of
the advised join point.
Friday, September 7, 2007 72
73. public aspect CirclingPolygons {
public double Polygon.getRadius()
{...}
public Point Polygon.getCenter()
{...}
}
Huh??
Friday, September 7, 2007 73
74. Introduction
Substitution Principle
Introductions must obey the
contract of the module.
Friday, September 7, 2007 74
75. public aspect PersistentAccount {
after (Account a): target(a) &&
call(* Account.setName()) {
persistName(a.getName());
}
}
What happens when “name” is refactored
to “firstName” and “lastName”??
Friday, September 7, 2007 75
76. Pointcut Inversion
Principle
Pointcuts should not depend upon
concrete details.
Pointcuts should depend upon
abstractions.
Friday, September 7, 2007 76
78. Components and
Frameworks
• Much hyped in the 90s
• All or nothing proposition
• ... due to internal dependencies
Can aspects reduce the coupling
and make them more reusable?
Friday, September 7, 2007 78
79. «aspect»
«aspect»
Client
Client
ClientService
ClientService
Service Service
Friday, September 7, 2007 79
80. Improved Architectures
• High-level defines policy
• Low-level defines details
Better separation using aspects?
Friday, September 7, 2007 80
81. Improved Architectures
• Domain-Specific Languages for the high-level
• Connect to low-level details with aspects
Friday, September 7, 2007 81
82. public class PersistenceDSL {
public PersistenceDSL() {
after()
.calling(methodsIn(
interface(StateChange.class)))
.then(persistChange());
}
}
(Fanciful, made-up example...)
Friday, September 7, 2007 82