{"id":456,"date":"2011-12-19T00:23:46","date_gmt":"2011-12-18T23:23:46","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=456"},"modified":"2011-12-19T00:23:46","modified_gmt":"2011-12-18T23:23:46","slug":"advanced-aspectj-part-iii-non-kinded-pointcuts","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=456","title":{"rendered":"Advanced AspectJ part III : non-kinded pointcuts"},"content":{"rendered":"<p> Today we will focus on non-kinded poincuts of AspectJ.<\/p>\n<p>Unlike kinded pointcuts (method execution, field access, object initialization &#8230;), non-kinded pointcuts select join point on some criteria other than the join point signature (no kind). For example it is possible to select join points inside the source code(lexical structure) of a Java class or method.  <\/p>\n<p><!--more--><\/p>\n<h1>I Case study<\/h1>\n<p>Below is a simple case study.<\/p>\n<p>Let&#8217;s say you need to code an exception logger for your application. This is a cross-cuting concern so you naturally think about AspectJ and <em>around()<\/em> pointcut, good thing !<\/p>\n<pre class=\"brush: java; highlight: [2]; title: ; wrap-lines: false; notranslate\" title=\"\">\n\t...\n\tpointcut exceptionPointCut(): execution(* com.myapp..*(..)) \n\t...\n\n\tObject around() : exceptionPointCut()\n\t{\n\t\tObject retValue = null;\n\t\t\n\t\ttry\n\t\t{\n\t\t\tretValue = proceed();\n\t\t}\n\t\tcatch(RuntimeException rte)\n\t\t{\n\t\t\t\/\/ Do something to process exception\n\t\t}\n\t\t\n\t\treturn retValue;\n\t}\n<\/pre>\n<p>What is wrong in the above aspect is not the <em>around()<\/em> advice itself, which is perfectly valid and sensitive. No, what is wrong is the design of pointcut. <\/p>\n<p>The problem with the exceptionPointCut() is that it is capturing far too many join points, more than necessary. But how can it be possible ? The pointcut restricts itself to execution of any method in the <strong>com.myapp<\/strong> package and all its sub-packages !<\/p>\n<p>Yes, but this restriction is not enough. It means that <strong>all methods execution<\/strong> in your application will be avised by this pointcut, which is quite alot.<\/p>\n<p>Ask yourself, <em>do I really need to track exceptions when calling getters\/setters for entities or DTO objects<\/em> ?  <em>Do I really need to track exceptions in stateless helper classes with a high unit test coverage<\/em> ?<\/p>\n<p>The idea is to restrict further the method execution join points. For this you have some options:<\/p>\n<ol>\n<li>\nbe more specific in the execution join point definition, by listing all classes you&#8217;ll like to monitor, it can be tedious: <em>execution(* com.myapp.xxx.Class1(..)) || execution(* com.myapp.xxx.Class1(..))<\/em> &#8230;<\/li>\n<p>&nbsp;<\/p>\n<li>\nbe more specific by giving a method name pattern. This is the most efficient strategy but it is not always applicable and is very use case-dependent : <em>execution(* com.myapp..do*(..))<\/em><\/li>\n<p>&nbsp;<\/p>\n<li>\nrely on <strong>non-kinded pointcuts<\/strong>, discussed below<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h1>II Non-kinded poincuts<\/h1>\n<p>There are 3 families of non-kinded pointcuts:<\/p>\n<ul>\n<li>control flow based: <strong>cflow<\/strong>(<em>[PoinCut]<\/em>) &amp; <strong>cflowbelow<\/strong>(<em>[PoinCut]<\/em>) : select all poincuts in the execution flow of the <em>[PointCut]<\/em>. The semantic of this pointcut has been discussed <a href=\"http:\/\/doanduyhai.wordpress.com\/2011\/12\/05\/advanced-aspectj-part-i-instanciation-model\/\" title=\"http:\/\/doanduyhai.wordpress.com\/2011\/12\/05\/advanced-aspectj-part-i-instanciation-model\" target=\"_blank\">here (Chapter I section C)<\/a><\/li>\n<p>&nbsp;<\/p>\n<li>source code based: <strong>within<\/strong>(<em>[TypeSignature]<\/em>) &amp; <strong>withincode<\/strong>(<em>[MethodSignature]<\/em>). <strong>within()<\/strong> will select all possible join points in the source code of the object(class, interface or aspect) specified by <em>[TypeSignature]<\/em>. <strong>withincode()<\/strong> selects all possible join points in the source code of the method defined by <em>[MethodSignature]<\/em>\n<\/li>\n<p>&nbsp;<\/p>\n<li>target-object based: <strong>this<\/strong>(<em>[TypeSignature]<\/em>) &amp; <strong>target<\/strong>(<em>[TypeSignature]<\/em>). <strong>this()<\/strong> selects all join points having this of type <em>[TypeSignature]<\/em> associated with them whereas <strong>target()<\/strong> selects all join points having target object of type <em>[TypeSignature]<\/em><\/li>\n<\/ul>\n<h2>A <em>within()<\/em><\/h2>\n<p>Examples are better than words, let&#8217;s look into the piece of code below:<\/p>\n<pre class=\"brush: java; highlight: [3,8,9,14,24,26,28]; title: ; wrap-lines: false; notranslate\" title=\"\">\npublic class DummyClass\n{\n\tprivate String name = &amp;quot;default&amp;quot;;\n\tprivate Date now;\n\n\tpublic void initialize()\n\t{\n\t\tthis.name = this.getClass().getCanonicalName();\n\t\tthis.now = new Date();\n\t}\n\n\tpublic String getData()\n\t{\n\t\treturn this.name + this.now.toString();\n\t}\n}\n\n\/\/ Runner class\npublic class TrackDummyClass\n{\n\n\tpublic static void main(String[] args)\n\t{\n\t\tDummyClass dummy = new DummyClass();\n\n\t\tdummy.initialize();\n\n\t\tdummy.getData();\n\t}\n}\n<\/pre>\n<p>Now we define an aspect using <em>within()<\/em> construct:<\/p>\n<pre class=\"brush: java; highlight: [5]; title: ; wrap-lines: false; notranslate\" title=\"\">\npublic aspect WithinAspects\n{\n\t\/\/ Matches all poincut in source code of com.techweb.test.DummyClass\n\t\/\/ static init, init, method execution &amp;amp; field access\n\tpointcut withinPoincut() : within(com.techweb.test.DummyClass);\n\t\n\tafter() : withinPoincut()\n\t{\n\t\tSystem.out.println(&amp;quot;Join Point : &amp;quot;+thisJoinPoint.toLongString());\n\t}\n}\n<\/pre>\n<p>Running the code will give the following output:<\/p>\n<p><code><br \/>\n<strong>\/\/ Init phase<\/strong><br \/>\nJoin Point : staticinitialization(static com.test.DummyClass.)<br \/>\nJoin Point : preinitialization(public com.test.DummyClass())<br \/>\nJoin Point : initialization(public com.test.DummyClass())<\/p>\n<p><strong>\/\/ Constructor call, line 24 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public com.test.DummyClass())<\/p>\n<p><strong>\/\/ line 3 in DummyClass<\/strong><br \/>\nJoin Point : set(private java.lang.String com.test.DummyClass.name) <\/p>\n<p><strong>\/\/ line 26 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public void com.test.DummyClass.initialize()) <\/p>\n<p><strong>\/\/ line 8 in DummyClass<\/strong><br \/>\nJoin Point : call(public final native java.lang.Class java.lang.Object.getClass())<br \/>\nJoin Point : call(public java.lang.String java.lang.Class.getCanonicalName())<br \/>\nJoin Point : set(private java.lang.String com.test.DummyClass.name)<\/p>\n<p><strong>\/\/ line 9 in DummyClass<\/strong><br \/>\nJoin Point : call(public java.util.Date())<br \/>\nJoin Point : set(private java.util.Date com.test.DummyClass.now)<\/p>\n<p><strong>\/\/ line 28 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public java.lang.String com.test.DummyClass.getData())<\/p>\n<p><strong>\/\/ line 14 in DummyClass<\/strong><br \/>\nJoin Point : get(private java.lang.String com.test.DummyClass.name)<br \/>\nJoin Point : call(public static java.lang.String<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.String.valueOf(java.lang.Object))<br \/>\nJoin Point : call(public java.lang.StringBuilder(java.lang.String))<br \/>\nJoin Point : get(private java.util.Date com.test.DummyClass.now)<br \/>\nJoin Point : call(public java.lang.String java.util.Date.toString())<br \/>\nJoin Point : call(public java.lang.StringBuilder<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.StringBuilder.append(java.lang.String))<br \/>\nJoin Point : call(public java.lang.String java.lang.StringBuilder.toString())<br \/>\n<\/code><\/p>\n<p><em>withincode()<\/em> is similar to <em>within()<\/em> except that it only applies to a method source code, not a type.<br \/>\n&nbsp;<\/p>\n<h2>B <em>this()<\/em><\/h2>\n<p>New let&#8217;s change <strong>within<\/strong>(com.techweb.test.DummyClass) by <strong>this<\/strong>(com.techweb.test.DummyClass) and look at the new output:<\/p>\n<p><code><br \/>\n<strong>\/\/ Init phase<\/strong><br \/>\nJoin Point : initialization(public com.test.DummyClass())<\/p>\n<p><strong>\/\/ Constructor call, line 24 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public com.test.DummyClass())<\/p>\n<p><strong>\/\/ line 3 in DummyClass<\/strong><br \/>\nJoin Point : set(private java.lang.String com.test.DummyClass.name) <\/p>\n<p><strong>\/\/ line 26 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public void com.test.DummyClass.initialize()) <\/p>\n<p><strong>\/\/ line 8 in DummyClass<\/strong><br \/>\nJoin Point : call(public final native java.lang.Class java.lang.Object.getClass())<br \/>\nJoin Point : call(public java.lang.String java.lang.Class.getCanonicalName())<br \/>\nJoin Point : set(private java.lang.String com.test.DummyClass.name)<\/p>\n<p><strong>\/\/ line 9 in DummyClass<\/strong><br \/>\nJoin Point : call(public java.util.Date())<br \/>\nJoin Point : set(private java.util.Date com.test.DummyClass.now)<\/p>\n<p><strong>\/\/ line 28 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public java.lang.String com.test.DummyClass.getData())<\/p>\n<p><strong>\/\/ line 14 in DummyClass<\/strong><br \/>\nJoin Point : get(private java.lang.String com.test.DummyClass.name)<br \/>\nJoin Point : call(public static java.lang.String<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.String.valueOf(java.lang.Object))<br \/>\nJoin Point : call(public java.lang.StringBuilder(java.lang.String))<br \/>\nJoin Point : get(private java.util.Date com.test.DummyClass.now)<br \/>\nJoin Point : call(public java.lang.String java.util.Date.toString())<br \/>\nJoin Point : call(public java.lang.StringBuilder<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.StringBuilder.append(java.lang.String))<br \/>\nJoin Point : call(public java.lang.String java.lang.StringBuilder.toString())<br \/>\n<\/code><\/p>\n<p>We can see that the output is almost identical to the one of <em>within()<\/em> except for the <strong>static initialization<\/strong> part, which is perfectly sensible.<br \/>\n&nbsp;<\/p>\n<h2>C <em>target()<\/em><\/h2>\n<p>Last experiment, let&#8217;s turn <strong>this<\/strong>(com.techweb.test.DummyClass) into <strong>target<\/strong>(com.techweb.test.DummyClass) and see how it modifies the output:<\/p>\n<p><code><br \/>\n<strong>\/\/ Init phase<\/strong><br \/>\nJoin Point : initialization(public com.techweb.test.DummyClass())<\/p>\n<p><strong>\/\/ Constructor call, line 24 in TrackDummyClass<\/strong><br \/>\nJoin Point : execution(public com.techweb.test.DummyClass())<\/p>\n<p><strong>\/\/ line 3 in DummyClass<\/strong><br \/>\nJoin Point : set(private java.lang.String com.techweb.test.DummyClass.name)<\/p>\n<p><strong>\/\/ line 26 in TrackDummyClass<\/strong><br \/>\nJoin Point : call(public void com.techweb.test.DummyClass.initialize())<br \/>\nJoin Point : execution(public void com.techweb.test.DummyClass.initialize())<\/p>\n<p><strong>\/\/ line 8 in DummyClass<\/strong><br \/>\nJoin Point : call(public final native java.lang.Class java.lang.Object.getClass())<br \/>\nJoin Point : set(private java.lang.String com.techweb.test.DummyClass.name)<\/p>\n<p><strong>\/\/ line 9 in DummyClass<\/strong><br \/>\nJoin Point : set(private java.util.Date com.techweb.test.DummyClass.now)<\/p>\n<p><strong>\/\/ line 28 in TrackDummyClass<\/strong><br \/>\nJoin Point : call(public java.lang.String com.techweb.test.DummyClass.getData())<\/p>\n<p><strong>\/\/ line 14 in DummyClass<\/strong><br \/>\nJoin Point : execution(public java.lang.String com.techweb.test.DummyClass.getData())<br \/>\nJoin Point : get(private java.lang.String com.techweb.test.DummyClass.name)<br \/>\nJoin Point : get(private java.util.Date com.techweb.test.DummyClass.now)<br \/>\n<\/code><\/p>\n<p> The produced output is quite interesting to analyze.<\/p>\n<p><code><br \/>\n<strong>\/\/ line 26 in TrackDummyClass : dummy.initialize();<\/strong><br \/>\nthis() version   : execution(public void com.techweb.test.DummyClass.initialize())<\/p>\n<p>target() version : call(public void com.techweb.test.DummyClass.initialize())<br \/>\ntarget() version : execution(public void com.techweb.test.DummyClass.initialize())<\/code><\/p>\n<p>With the <em>target()<\/em> construct, we capture not only the method call on the DummyClass but also the method execution.<\/p>\n<p><code><br \/>\n<strong>\/\/ line 8 in DummyClass : this.name = this.getClass().getCanonicalName();<\/strong><br \/>\nthis() version   : call(public final native java.lang.Class java.lang.Object.getClass())<br \/>\nthis() version   : call(public java.lang.String java.lang.Class.getCanonicalName())<br \/>\nthis() version   : set(private java.lang.String com.test.DummyClass.name)<\/p>\n<p>target() version : call(public final native java.lang.Class java.lang.Object.getClass())<br \/>\ntarget() version : set(private java.lang.String com.techweb.test.DummyClass.name)<\/code><\/p>\n<p>This time, with the <em>this()<\/em> construct, we can capture the call to <strong>java.lang.Class.getCanonicalName()<\/strong>. The <em>target()<\/em> construct cannot capture this call because indeed, the target object for the method call is the class <strong>java.lang.Class<\/strong> and not DummyClass.<br \/>\n&nbsp;<\/p>\n<h1>III Back to case study<\/h1>\n<p>Now that we&#8217;ve explained the non-kinded poincuts, let&#8217;s see how they can be applied to our exception tracker use case.<\/p>\n<p>To restrict further matching join points, we could use the within() construct to only select join points inside particular packages:<\/p>\n<pre class=\"brush: java; highlight: [2,3,4,5]; title: ; wrap-lines: false; notranslate\" title=\"\">\n\t...\n\tpointcut exceptionPointCut(): execution(* com.myapp..*(..)) &amp;amp;&amp;amp; (\n\t\twithin(com.myapp.service..*)\n\t\t|| within(com.myapp.web..*)\n\t\t|| within(com.myapp.dao..*)\n\t\t);\n\t...\n<\/pre>\n<p>The above poincut selects:<\/p>\n<ul>\n<li>all method executions in the package <strong>com.myapp<\/strong> and its sub-package<\/li>\n<li>restricted to the packages <strong>com.myapp.service<\/strong> or <strong>com.myapp.web<\/strong> or <strong>com.myapp.dao<\/strong><\/li>\n<\/ul>\n<p>In a nutshell, we restrict the exception tracking to all method execution in service, controller or dao layer.<\/p>\n<p>Of course it is possible to define finer filtering based on method name. This example just show the convenience of non-kinded pointcuts.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we will focus on non-kinded poincuts of AspectJ. Unlike kinded pointcuts (method execution, field access, object initialization &#8230;), non-kinded pointcuts select join point on some criteria other than the join point signature (no kind). For example it is possible&#8230;<br \/><a class=\"read-more-button\" href=\"https:\/\/www.doanduyhai.com\/blog\/?p=456\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3,9],"tags":[33,42],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/456"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=456"}],"version-history":[{"count":0,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/456\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=456"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=456"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=456"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}