Talk:AOP
From APIDesign
(Comment provided by btilford - via ArticleComments extension) |
|||
Line 40: | Line 40: | ||
--[[User:JaroslavTulach|JaroslavTulach]] 08:46, 19 November 2009 (UTC) | --[[User:JaroslavTulach|JaroslavTulach]] 08:46, 19 November 2009 (UTC) | ||
+ | == btilford said ... == | ||
+ | |||
+ | <div class='commentBlock'> | ||
+ | I did a pretty bad job explaining how it works... ;) | ||
+ | |||
+ | So basically someone could create a library with an annotation and an "Aspect" | ||
+ | <source lang="java"> | ||
+ | @Inherited | ||
+ | @Documented | ||
+ | @Target(ElementType.METHOD) | ||
+ | @Retention(RetentionPolicy.RUNTIME) | ||
+ | public @interface BoundProp { | ||
+ | String value(); | ||
+ | } | ||
+ | </source> | ||
+ | <source lang="java"> | ||
+ | @Aspect | ||
+ | @Component | ||
+ | public class BoundPropertyAspect { | ||
+ | |||
+ | private static final String SETTER = "^set"; | ||
+ | //execution(public * *(..)) | ||
+ | @Around( | ||
+ | "@annotation(test.BoundProp) && execution(public * *..*.set*(*))") | ||
+ | private void propertyChanged(ProceedingJoinPoint joinPoint) { | ||
+ | Logger.getLogger(getClass().getName()).info("Advice propertyChanged"); | ||
+ | |||
+ | SourceLocation source = joinPoint.getSourceLocation(); | ||
+ | // Logger.getLogger(getClass().getName()).info("\tSource: " + source.getFileName() + " (" + source.getLine() + ")"); | ||
+ | |||
+ | Object owner = joinPoint.getTarget(); | ||
+ | Logger.getLogger(getClass().getName()).info("\tOwner: " + owner.getClass().getName()); | ||
+ | |||
+ | Object newValue = joinPoint.getArgs()[0]; | ||
+ | Logger.getLogger(getClass().getName()).info("\tnewValue: " + newValue.toString()); | ||
+ | |||
+ | |||
+ | String setter = joinPoint.getSignature().getName(); | ||
+ | Logger.getLogger(getClass().getName()).info("\tmethodName: " + setter); | ||
+ | |||
+ | |||
+ | PropertyChangeSupport pcs = null; | ||
+ | |||
+ | Object old = null; | ||
+ | try { | ||
+ | old = | ||
+ | owner.getClass().getMethod( | ||
+ | setter.replaceFirst(SETTER, "get")).invoke(owner); | ||
+ | pcs = | ||
+ | (PropertyChangeSupport) owner.getClass().getMethod( | ||
+ | "getPropertyChangeSupport").invoke(owner); | ||
+ | |||
+ | } catch (Throwable ex) { | ||
+ | Logger.getLogger(BoundPropertyAspect.class.getName()).log( | ||
+ | Level.SEVERE, | ||
+ | null, ex); | ||
+ | } finally { | ||
+ | try { | ||
+ | joinPoint.proceed(); | ||
+ | } catch (Throwable ex) { | ||
+ | Logger.getLogger(BoundPropertyAspect.class.getName()).log( | ||
+ | Level.SEVERE, | ||
+ | null, ex); | ||
+ | } | ||
+ | } | ||
+ | if (pcs != null) { | ||
+ | pcs.firePropertyChange(setter.replaceFirst(SETTER, ""), old, | ||
+ | newValue); | ||
+ | } | ||
+ | |||
+ | |||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Then that aspect could be "triggered" by annotating a method with the @BoundProp annotation | ||
+ | <source lang="java"> | ||
+ | class SomeClass { | ||
+ | @BoundProp | ||
+ | void setSomething(Object singleArg) {...} | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | --btilford 05:53, 20 November 2009 (CET) | ||
+ | </div> |
Revision as of 04:53, 20 November 2009
Comments on AOP <comments />
NicolasDumoulin said ...
Well, Nicolas, you are able to debug Netigso, so you cannot be counted into the target group that can practise only empiristic programming and needs as much simplicity as possible. But I agree that with Maven the compile time configuration is much more simplified than I have envisioned.
--JaroslavTulach 08:51, 19 November 2009 (UTC)
btilford said ...
AspectJ supports annotations pretty well plus you still have all the old methods of defining a pointcut (or combination) if you need to really specific.
e.g.
@Around("@annotation(com.mycompany.BoundProp)")
would match all methods annotated with @com.mycompany.BoundProp
and you could still say only setters with 1 argument should be bound (since it might make sense to do that)
@Around("@annotation(com.mycompany.BoundProp) && execution(public * *..*.set*(*))")
--btilford 01:45, 19 November 2009 (CET)
Thanks for your comment btilford. I did not know this. Still, this is slightly opposite approach. The end user still needs to deal with aspect and with meaning of @Around and pointcut public * *..*.set*(*)) and setup the AspectJ compiler. I'm seeking for the possite: The user downloads library with com.mycompany.BoundProp annotations, applies the annotation to one of its classes and as a result all the setters in the class will become bounded. This is not big shift technologically, I guess, but huge improvement in ease of use. Not talking about the fact that it opens the door to create a market of reusable aspects.
--JaroslavTulach 08:46, 19 November 2009 (UTC)
btilford said ...
I did a pretty bad job explaining how it works... ;)
So basically someone could create a library with an annotation and an "Aspect"
@Inherited @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface BoundProp { String value(); }
@Aspect @Component public class BoundPropertyAspect { private static final String SETTER = "^set"; //execution(public * *(..)) @Around( "@annotation(test.BoundProp) && execution(public * *..*.set*(*))") private void propertyChanged(ProceedingJoinPoint joinPoint) { Logger.getLogger(getClass().getName()).info("Advice propertyChanged"); SourceLocation source = joinPoint.getSourceLocation(); // Logger.getLogger(getClass().getName()).info("\tSource: " + source.getFileName() + " (" + source.getLine() + ")"); Object owner = joinPoint.getTarget(); Logger.getLogger(getClass().getName()).info("\tOwner: " + owner.getClass().getName()); Object newValue = joinPoint.getArgs()[0]; Logger.getLogger(getClass().getName()).info("\tnewValue: " + newValue.toString()); String setter = joinPoint.getSignature().getName(); Logger.getLogger(getClass().getName()).info("\tmethodName: " + setter); PropertyChangeSupport pcs = null; Object old = null; try { old = owner.getClass().getMethod( setter.replaceFirst(SETTER, "get")).invoke(owner); pcs = (PropertyChangeSupport) owner.getClass().getMethod( "getPropertyChangeSupport").invoke(owner); } catch (Throwable ex) { Logger.getLogger(BoundPropertyAspect.class.getName()).log( Level.SEVERE, null, ex); } finally { try { joinPoint.proceed(); } catch (Throwable ex) { Logger.getLogger(BoundPropertyAspect.class.getName()).log( Level.SEVERE, null, ex); } } if (pcs != null) { pcs.firePropertyChange(setter.replaceFirst(SETTER, ""), old, newValue); } } }
Then that aspect could be "triggered" by annotating a method with the @BoundProp annotation
class SomeClass { @BoundProp void setSomething(Object singleArg) {...} }
--btilford 05:53, 20 November 2009 (CET)
We use aspectj for defining and using an aspect that serve an automatic objects caching service. It's not so hard, you can see our notes here: http://www.simexplorer.org/wiki/DevDoc/AspectJ
--NicolasDumoulin 13:00, 13 November 2009 (CET)