Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Aspect Oriented Programming (Internal Brown Bag...

Aspect Oriented Programming (Internal Brown Bag Lunch 2015)

An introduction to the concepts of AOP, with Java examples.
Internal presentation at Deezer's Brown Bag Lunch

Xavier Gouchet

April 15, 2015
Tweet

More Decks by Xavier Gouchet

Other Decks in Programming

Transcript

  1. Enhance modularity Separate cross cutting concerns Separate business logic from

    tech code Reduce noise in the source code What is it ?
  2. Before Example After void doSomething() { log(“doSomething”); beginTransaction(); try {

    callMethod(); ... setTransactionSuccessful(); } catch (e) { reportError(e); } finally { endTransaction(); } log(“done”); } @SafeTransaction void doSomething() { callMethod(); ... }
  3. Attributs (visual aspects) applied to <Elements/> (markup nodes in source

    code) based on Selectors (rules / pattern) Widely used on the web since 1996
  4. Hello World @interface TraceLog{} public class MyClass { @TraceLog public

    void foo() { // … } } @Aspect public class TraceLogAspect { @Pointcut(“execution(@TraceLog * *(..))”) public void traceLogMethod(){} @Before(“traceLogMethod()”) public void advice(JoinPoint jp) { Logger.log(“> ” + jp.getSignature()); } }
  5. @Aspect public class PerformanceMonitorAspect { @Pointcut(“execution(@Monitor * *(..))”) public void

    monitoredMethod(){} @Around(“monitoredMethod()”) public void advice(ProceedingJoinPoint jp) { long start = getCurrentTime(); jp.proceed(); long end = getCurrentTime(); // ... } } @interface Monitor{} public class MyClass { @Monitor public void foo() { // … } } Performance
  6. @Aspect public class DBTransactionAspect { @Around(“execution(@Transaction * *(..)) && args(db,

    ..)”) public void advice(ProceedingJoinPoint jp, SQLiteDatabase db) { db.beginTransaction(); try { jp.proceed(); db.setTransactionSuccessful(); } catch (SQLiteException e) { // ... } finally { db.endTransaction(); } } } Transactions
  7. Validation @interface Validate{ String regexp() default “.*”; } public class

    MyClass { @Validate(regexp=“[a-zA-Z0-9_-]{3-15}”) public void setUserName(String userName) { // … } @Validate(regexp=“((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})”) public void setPassword(String password) { // … } @Validate(regexp=“[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}”) public void setEmail(String userName) { // … } }
  8. @Aspect public class InputValidationAspect { @Before(“execution(@Validate * *(..)) && args(input,

    ..)”) public void advice(JoinPoint jp, String input) { Validate v = jp.getSignature() .getMethod() .getAnnotation(Validate.class); Pattern pattern = Pattern.compile(v.regexp()); Matcher matcher = pattern.matcher(input); if (!matcher.matches()) { throw new InvalidInputException(); } } } Validation
  9. Undo / Redo interface IUndoableAction { public void undo(); public

    void redo(); } class UndoManager { public void record(IUndoableAction action) { // ... } }
  10. Undo / Redo class UndoableFieldAction { Field field; Object target,

    oldValue, newValue; public UndoableFieldAction(Object t, Field f, Object ov, Object nv) { field = f; target = t; oldValue = ov; newValue = nv; } public void undo(){ field.set(target, oldValue); } public void redo(){ field.set(target, newValue); } }
  11. Undo / Redo @Aspect public class UndoActionAspect { @Pointcut(“within(com.example.model.*)”) public

    void withinModelClass() {} @Pointcut(“set(public * *)”) public void setPublicField() {} @Before(“withinModelClass() && setPublicField() && args(val) && target(obj)”) public void advice(JoinPoint jp, Object obj, Object val) { Field field = getField(jp, obj); Object oldValue = field.get(obj); UndoManager.getInstance() .record(new UndoableFieldAction(obj, field, oldValue, val); } }
  12. Security / Gatekeeping enum Role { ADMIN, USER, ANONYMOUS }

    @interface GateKeep { Role[] allowed(); } @GateKeep(allowed = {ADMIN, USER}) public void foo() { // ... }
  13. @Aspect public class SecurityAspect { @Around(“execution(@GateKeep * *(..))”) public void

    advice(ProceedingJoinPoint jp) { GateKeep gate = jp.getSignature() .getMethod() .getAnnotation(GateKeep.class); Role userRole = UserService.getInstance() .getCurrentUser() .getRole(); if (Arrays.asList(gate.allowedRoles()).contains(userRole)) { jp.proceed(); } } } Security / Gatekeeping
  14. MultiThreading @Aspect public class UIThreadAspect { @Around(“execution(@UIThread * *(..))”) public

    void advice(final ProceedingJoinPoint jp) { Runnable task = new Runnable() { public void run() { jp.proceed(); } }; new Handler(Looper.getMainLooper()).post(task); } }
  15. Compile Time Checks @Aspect public class CoreCheckAspect { @Pointcut(“within(com.example.core.*)”) public

    void withinCorePackage() {} @Pointcut(“call(* com.example.ui..*..*(..))”) public void callToUIMethod() {} @DeclareError(“withinCorePackage() && callToUIMethod()”) static final String MESSAGE = “Core classes should not call UI methods”; }
  16. The “Pokeball” Pointcut (Gotta catch’em all) The “Octopuss” Pointcut Asp’ception

    (Because advice can be caught by pointcut too) The Aspector Gadget (An aspect with more advices than you can count) Errors to avoid