<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-23435402</id><updated>2012-02-10T23:44:37.035-08:00</updated><category term='Scala'/><category term='AspectJ'/><category term='JVM'/><category term='Spring'/><category term='XSLT'/><category term='Generics'/><category term='Java'/><category term='Lazy loading'/><category term='JAXB'/><category term='Hadoop'/><category term='mixed content'/><category term='Transactions'/><title type='text'>Judge Mental</title><subtitle type='html'>A blog about code and, occasionally, politics</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-23435402.post-6471256453059040513</id><published>2012-01-03T18:24:00.000-08:00</published><updated>2012-01-05T02:46:17.167-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><title type='text'>Uses of wildcard types in Java</title><content type='html'>Many of the Java coding questions I get from my colleagues come down to confusion about wildcard types in Java generics.  I'll be editing this post on an ongoing basis to catalog all the ways I have productively used these beasts.&lt;h4&gt;Uses of wildcard types&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Compile-time prevention of incremental modifications to a collection.&lt;/strong&gt;  Because the &lt;code&gt;put()&lt;/code&gt; and &lt;code&gt;add()&lt;/code&gt; methods of most collection abstractions receive an argument of the element type, the compiler will prevent you from even attempting to call these methods on a variable of type &lt;code&gt;Collection&amp;lt;&amp;nbsp;? extends &lt;var&gt;T&lt;/var&gt;&amp;nbsp;&amp;gt;&lt;/code&gt; for any type or type parameter &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt;.  Unfortunately, you &lt;em&gt;can&lt;/em&gt; still call &lt;code&gt;Collection.clear()&lt;/code&gt; with no error, so the collection is not completely statically protected from modification.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Compile-time enforcement of write-only collections.&lt;/strong&gt;  The converse of the above is that the &lt;code&gt;get()&lt;/code&gt; methods don't work on a variable of type &lt;code&gt;Collection&amp;lt;&amp;nbsp;? super &lt;var&gt;T&lt;/var&gt;&amp;nbsp;&amp;gt;&lt;/code&gt; unless the receiving type is &lt;code&gt;Object&lt;/code&gt;, which is usually the wrong thing to do anyway.  However you can happily &lt;code&gt;put()&lt;/code&gt; and &lt;code&gt;add()&lt;/code&gt; &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt;s to such a collection (and of course you can call &lt;code&gt;clear()&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Broader applicability of parametric library methods.&lt;/strong&gt;  If you have, for example, a utility &lt;code&gt;forAll()&lt;/code&gt; which iterates over a collection of elements of type &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt; (and does not use that collection in any other way), the argument type should be &lt;code&gt;Iterable&amp;lt;&amp;nbsp;? extends &lt;var&gt;T&lt;/var&gt;&amp;nbsp;&amp;gt;&lt;/code&gt;, and not, say, &lt;code&gt;List&amp;lt;&amp;nbsp;&lt;var&gt;T&lt;/var&gt;&amp;nbsp;&amp;gt;&lt;/code&gt;, and you should probably have an &lt;code&gt;Iterator&amp;lt;&amp;nbsp;? extends &lt;i&gt;T&lt;/i&gt;&amp;nbsp;&amp;gt;&lt;/code&gt; overload as well.  If &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt; were &lt;code&gt;CharSequence&lt;/code&gt;, for example, you could call &lt;code&gt;forAll( Arrays.asList( "a", "b", "c" ) )&lt;/code&gt; or &lt;code&gt;forAll( new HashSet&amp;lt;&amp;nbsp;StringBuilder&amp;nbsp;&amp;gt;() )&lt;/code&gt; without needing extra copies of the utility logic, casts, or pointless reference copies.  If your method requires a more complex nested type, you should use as many wildcards as are allowed, as in &lt;code&gt;Map&amp;lt;&amp;nbsp;? extends &lt;var&gt;K&lt;/var&gt;, ? extends Iterable&amp;lt;&amp;nbsp;? extends &lt;var&gt;V&lt;/var&gt;&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Broader utility of parametric library methods.&lt;/strong&gt; Continuing the above example: because Java has no easy way to do a higher-order method like &lt;code&gt;map()&lt;/code&gt; or &lt;code&gt;filter()&lt;/code&gt; on collections, you will likely be writing loops in utility methods.  Say we are writing a method that iterates a collection, looking for some property of the elements, and produces a new list with only the elements of the original list that had the property in question.  It is better to declare the interface like&lt;pre&gt;&lt;br /&gt;public static List&amp;lt;&amp;nbsp;T&amp;nbsp;&amp;gt; filter( Iterable&amp;lt;&amp;nbsp;? extends T&amp;nbsp;&amp;gt; it );&lt;/pre&gt; than &lt;pre&gt;&lt;br /&gt;public static List&amp;lt;&amp;nbsp;T&amp;nbsp;&amp;gt; filter( Iterable&amp;lt;&amp;nbsp;T&amp;nbsp;&amp;gt; it );&lt;/pre&gt;  Why? Say we have a &lt;code&gt;s&lt;/code&gt; of type &lt;code&gt;Set&amp;lt;&amp;nbsp;? extends Person&amp;nbsp;&amp;gt;&lt;/code&gt;.  In the latter case, Java will infer the return type of &lt;code&gt;filter( s )&lt;/code&gt; to be &lt;code&gt;List&amp;lt;&amp;nbsp;? extends Person&amp;nbsp;&amp;gt;&lt;/code&gt;, which can't be used directly by some other method needing a &lt;code&gt;List&amp;lt;&amp;nbsp;Person&amp;nbsp;&amp;gt;&lt;/code&gt;; not all APIs are considerate enough to follow the protocol in use number 3, above, which leaves them subject to quirk number 3, below. Perhaps surprisingly, in the former case, Java infers a return type of &lt;code&gt;List&amp;lt;&amp;nbsp;Person&amp;nbsp;&amp;gt;&lt;/code&gt; for the call &lt;code&gt;filter( s )&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;More flexible class implementations.&lt;/strong&gt;  Generic collaborators (such as &lt;code&gt;Comparator&lt;/code&gt;s) to whom you only &lt;i&gt;supply&lt;/i&gt; &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt;s should be typed using &lt;code&gt;? super &lt;var&gt;T&lt;/var&gt;&lt;/code&gt;, and collaborators from whom you only &lt;i&gt;get&lt;/i&gt; &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt;s should be typed using &lt;code&gt;? extends &lt;var&gt;T&lt;/var&gt;&lt;/code&gt;.  Note that these collaborators might very well be invariant in their type parameters (that is, there may be methods for consuming and producing &lt;code&gt;&lt;var&gt;T&lt;/var&gt;&lt;/code&gt;s available); but if you only &lt;i&gt;use&lt;/i&gt; one sort or the other, you should still use wildcards to allow covariance or contravariance, whichever is compatible.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Making up for Java's lame type inference.&lt;/strong&gt;  The following innocuous-looking code will not compile as is:&lt;pre&gt;&lt;br /&gt;List&amp;lt;&amp;nbsp;List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt; llstr = Arrays.asList( new ArrayList&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;() );&lt;br /&gt;&lt;/pre&gt;The reason is that the compiler infers the type &lt;code&gt;List&amp;lt;&amp;nbsp;ArrayList&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt;&lt;/code&gt; for the right-hand side of the assignment, which is not assignment-compatible with &lt;code&gt;List&amp;lt;&amp;nbsp;List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt;&lt;/code&gt; (see quirk number 2, below).  Any of the following edits &lt;em&gt;will&lt;/em&gt; compile, however.&lt;pre&gt;&lt;br /&gt;// eschew type inference&lt;br /&gt;List&amp;lt;&amp;nbsp;List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt; llstr = Arrays.&amp;lt;&amp;nbsp;List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt;asList( new ArrayList&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;() );&lt;br /&gt;// use a cast (horrors!)&lt;br /&gt;List&amp;lt;&amp;nbsp;List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt; llstr = Arrays.asList( ( &amp;lt;&amp;nbsp;List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt; )new ArrayList&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;() );&lt;br /&gt;// use a wildcard in the variable type&lt;br /&gt;List&amp;lt;&amp;nbsp;? extends List&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;&amp;nbsp;&amp;gt; llstr = Arrays.asList( new ArrayList&amp;lt;&amp;nbsp;String&amp;nbsp;&amp;gt;() );&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h4&gt;Potential use of wildcard types, if only the damn language would allow it&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Anonymous intersection types.&lt;/strong&gt;  Suppose you want to act on a collection of objects that implement the two interfaces &lt;code&gt;&lt;var&gt;I&lt;/var&gt;&lt;/code&gt; and &lt;code&gt;&lt;var&gt;J&lt;/var&gt;&lt;/code&gt; (the technique works for any finite number of interfaces and optionally 1 class).  Your method signature could look like&lt;pre&gt;&lt;br /&gt;public void doSomething( List&amp;lt;&amp;nbsp;? extends &lt;var&gt;I&lt;/var&gt; &amp;amp; &lt;var&gt;J&lt;/var&gt;&amp;nbsp;&amp;gt; lij ); // won't compile&lt;br /&gt;&lt;/pre&gt;except that constraints are only allowed where type parameters are declared (i.e., &lt;code&gt;class C&amp;lt;&amp;nbsp;T extends I &amp;amp; J&amp;nbsp;&amp;gt; {}&lt;/code&gt;, &lt;code&gt;interface E&amp;lt;&amp;nbsp;T extends I &amp;amp; J&amp;nbsp;&amp;gt; {}&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;nbsp;T extends I &amp;amp; J&amp;nbsp;&amp;gt; void f() {}&lt;/code&gt;.  You are thus reduced to giving a name to the intersection type, as in&lt;pre&gt;&lt;br /&gt;public &amp;lt;&amp;nbsp;IJ extends &lt;var&gt;I&lt;/var&gt; &amp;amp; &lt;var&gt;J&lt;/var&gt;&amp;nbsp;&amp;gt; void doSomething( List&amp;lt;&amp;nbsp;IJ&amp;nbsp;&amp;gt; lij );&lt;br /&gt;&lt;/pre&gt;An advantage of using a name instead of a wildcard is that this technique works directly with a &lt;em&gt;single&lt;/em&gt; argument of both interfaces:&lt;pre&gt;&lt;br /&gt;public &amp;lt;&amp;nbsp;IJ extends &lt;var&gt;I&lt;/var&gt; &amp;amp; &lt;var&gt;J&lt;/var&gt;&amp;nbsp;&amp;gt; void doSomething( IJ ij ) {&lt;br /&gt;    // ...&lt;br /&gt;    ij.iMethod();&lt;br /&gt;    ij.jMethod();&lt;br /&gt;    iConsumer( ij );&lt;br /&gt;    jConsumer( ij );&lt;br /&gt;    // ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h4&gt;Quirks of wildcard types&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;You can't construct an instance of a wildcard type using &lt;code&gt;new&lt;/code&gt;.&lt;/strong&gt;  You &lt;i&gt;can&lt;/i&gt;, however, use a factory method to accomplish the same thing, which makes me wonder why the designers of Java didn't just make &lt;code&gt;new&lt;/code&gt; work.  Given&lt;pre&gt;class C&amp;lt; T &amp;gt; {&lt;br /&gt;    public C() {}&lt;br /&gt;    public static &amp;lt; T &amp;gt; C&amp;lt; T &amp;gt; make() {&lt;br /&gt;        return new C&amp;lt; T &amp;gt;();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;the following lines (using type inference) are ok:&lt;pre&gt;C&amp;lt; ? extends T &amp;gt; ct = C.make();&lt;br /&gt;C&amp;lt; ? super T &amp;gt; ct = C.make();&lt;/pre&gt;but the following won't compile ("wildcard not allowed at this location"):&lt;pre&gt;C&amp;lt; ? extends T &amp;gt; ct = new C&amp;lt; ? extends T &amp;gt;();&lt;br /&gt;C&amp;lt; ? super T &amp;gt; ct = new C&amp;lt; ? super T &amp;gt;();&lt;br /&gt;C&amp;lt; ? super T &amp;gt; ct = C.&amp;lt;&amp;nbsp;? super T&amp;nbsp;&amp;gt;make();&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Generic types are invariant in their type parameters.&lt;/strong&gt;  In simpler terms, a &lt;code&gt;C&amp;lt;&amp;nbsp;Employee&amp;nbsp;&amp;gt;&lt;/code&gt; is not a &lt;code&gt;C&amp;lt;&amp;nbsp;Person&amp;nbsp;&amp;gt;&lt;/code&gt;, even if it should be by all rights (for example, if there are no methods consuming the parameter type &lt;code&gt;T&lt;/code&gt; in &lt;code&gt;C&amp;lt;&amp;nbsp;T&amp;nbsp;&amp;gt;&lt;/code&gt;).  The opposite relationship also does not hold, even if it should by all rights.  Instead, you get to make either relationship hold at the point where such objects are used, usually &lt;i&gt;by using wildcard types&lt;/i&gt;.  A &lt;code&gt;C&amp;lt;&amp;nbsp;Employee&amp;nbsp;&amp;gt;&lt;/code&gt; &lt;i&gt;is&lt;/i&gt; a &lt;code&gt;C&amp;lt;&amp;nbsp;? extends Person&amp;nbsp;&amp;gt;&lt;/code&gt;, and a &lt;code&gt;C&amp;lt;&amp;nbsp;Person&amp;nbsp;&amp;gt;&lt;/code&gt; &lt;i&gt;is&lt;/i&gt; a &lt;code&gt;C&amp;lt;&amp;nbsp;? super Employee&amp;nbsp;&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Wildcard types are supertypes.&lt;/strong&gt;  A &lt;code&gt;C&amp;lt;&amp;nbsp;Person&amp;nbsp;&amp;gt;&lt;/code&gt; &lt;i&gt;is&lt;/i&gt; a &lt;code&gt;C&amp;lt;&amp;nbsp;? extends Person&amp;nbsp;&amp;gt;&lt;/code&gt; and also a &lt;code&gt;C&amp;lt;&amp;nbsp;? super Person&amp;nbsp;&amp;gt;&lt;/code&gt;.  No other relationships hold between the three types.  It is for this reason that I advocate interfaces like uses 3 and 4, above; a method declared to expect a &lt;code&gt;List&amp;lt;&amp;nbsp;Person&amp;nbsp;&amp;gt;&lt;/code&gt; is just not going to accept a &lt;code&gt;List&amp;lt;&amp;nbsp;? extends Person&amp;nbsp;&amp;gt;&lt;/code&gt; or a &lt;code&gt;List&amp;lt;&amp;nbsp;Employee&amp;nbsp;&amp;gt;&lt;/code&gt;, even if it only consumed elements from the input as &lt;code&gt;Person&lt;/code&gt;s.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-6471256453059040513?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/6471256453059040513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=6471256453059040513' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/6471256453059040513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/6471256453059040513'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2012/01/uses-of-wildcard-types-in-java.html' title='Uses of wildcard types in Java'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-3505678421213448701</id><published>2011-08-05T12:21:00.000-07:00</published><updated>2011-08-05T12:23:17.582-07:00</updated><title type='text'>Requirements for using a Hadoop combiner</title><content type='html'>One way to reduce I/O for large Hadoop jobs, especially those whose mappers produce many records with relatively fewer distinct keys, is to introduce a combiner phase between the mapper and reducer.  I have not seen a simple diagram explaining what the types should be for the combiner and what properties the algorithm must exhibit, so here goes.  If your mapper extends &lt;code&gt;Mapper&amp;lt; K1, V1, K2, V2 &amp;gt;&lt;/code&gt; and your reducer extends &lt;code&gt;Reducer&amp;lt; K2, V2, K3, V3 &amp;gt;&lt;/code&gt;, then the combiner must be an extension of &lt;code&gt;Reducer&amp;lt; K2, V2, K2, V2 &amp;gt;&lt;/code&gt;, and the following diagram must commute:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center; margin-left:-1em"&gt;&lt;a href="http://4.bp.blogspot.com/-sZ-2TfmS69A/TjxCBO01L4I/AAAAAAAAAHY/f2zqLfZ5LUE/s1600/CombinerDiagram.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="126" width="640" src="http://4.bp.blogspot.com/-sZ-2TfmS69A/TjxCBO01L4I/AAAAAAAAAHY/f2zqLfZ5LUE/s640/CombinerDiagram.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The triangle in the center of the diagram represents distributivity of the combiner function (i.e., &lt;code&gt;reduce&lt;/code&gt;(k, &lt;code&gt;combine&lt;/code&gt;(k, M)) = &lt;code&gt;reduce&lt;/code&gt;(k, &lt;code&gt;combine&lt;/code&gt;(k, &amp;cup;&lt;sub&gt;i&lt;/sub&gt;&lt;code&gt;combine&lt;/code&gt;(k,&amp;sigma;&lt;sub&gt;i&lt;/sub&gt;(M))) for any partition &amp;sigma; = {&amp;sigma;&lt;sub&gt;i&lt;/sub&gt; | i &amp;isin; I} of M), because Hadoop does not guarantee how many times it will combine intermediate outputs, if at all.&lt;br /&gt;&lt;br /&gt;A common pattern is to use the same function for combiner and reducer, but for this pattern to work, we must have &lt;code&gt;K2 = K3&lt;/code&gt; and &lt;code&gt;V2 = V3&lt;/code&gt; (and of course, the reducer itself must be distributive).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-3505678421213448701?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/3505678421213448701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=3505678421213448701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/3505678421213448701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/3505678421213448701'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2011/08/requirements-for-using-hadoop-combiner.html' title='Requirements for using a Hadoop combiner'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-sZ-2TfmS69A/TjxCBO01L4I/AAAAAAAAAHY/f2zqLfZ5LUE/s72-c/CombinerDiagram.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-3511172080358829163</id><published>2011-06-16T22:05:00.000-07:00</published><updated>2011-07-30T22:57:56.642-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Escaping property placeholders in Spring XML config</title><content type='html'>&lt;h4&gt;The problem&lt;/h4&gt;You might have encountered the awkward situation in which you are&lt;br /&gt;&lt;ol&gt;&lt;li&gt;using Spring and XML config&lt;/li&gt;&lt;li&gt;substituting properties into that config via some PropertyPlaceholderConfigurator&lt;/li&gt;&lt;li&gt;needing to set some value in the config to a literal string of the form "${identifier}"&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;By default, any string of the form in 3. above is a placeholder, and if you have no value for that placeholder, you get an exception.  Spring JIRA &lt;a href="https://jira.springsource.org/browse/SPR-4953"&gt;issue SPR-4953&lt;/a&gt;, which recognizes the fact that there is no simple escaping syntax for placeholders, is still open as of this writing.&lt;br /&gt;&lt;br /&gt;A snippet such as the following will cause the exception if there is no value available to substitute for the variable &lt;code&gt;customerName&lt;/code&gt;, or actually substitute a value for it if it is available.  Neither result is desirable in our scenario; we want the "&lt;code&gt;${customerName}&lt;/code&gt;" to remain intact when it is injected into our bean.&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="aTrickyBean" class="org.anic.veggies.AreGoodForYou"&amp;gt;&lt;br /&gt;    &amp;lt;constructor-arg name="expression" value="Hello, ${customerName}!"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Most workarounds I have seen are unsatisfactory.  You can use a customized placeholder configurator that sets its delimiter characters to something other than the default, for example, which would mean you would have to change the look of all the actual (unescaped) placeholders just to support the ones you want escaped.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The workaround&lt;/h4&gt;However, in Spring 3.x, you can work around this issue in a much more simple way using the following trick with SpEL:&lt;br /&gt;&lt;pre&gt;&amp;lt;bean id="aTrickyBean" class="org.anic.veggies.AreGoodForYou"&amp;gt;&lt;br /&gt;    &amp;lt;constructor-arg name="expression" value="#{ 'Hello, $' + '{customerName}!' }"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;Note that in order for this trick to work it is vital that the '$' and the '{' be physically separated (in this case, on either side of a string concatenation).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-3511172080358829163?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/3511172080358829163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=3511172080358829163' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/3511172080358829163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/3511172080358829163'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2011/06/escaping-property-placeholders-in.html' title='Escaping property placeholders in Spring XML config'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-2798943421721450535</id><published>2010-11-11T00:41:00.000-08:00</published><updated>2012-01-20T10:36:37.617-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hadoop'/><title type='text'>Random notes on Hadoop</title><content type='html'>I am talking about Hadoop 0.20 using a custom jar, not streaming or Hive or Pig.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Make sure your distribution has the MAPREDUCE-1182 patch.&lt;/li&gt;&lt;li&gt;Make sure you change the default setting of &lt;code&gt;dfs.datanode.max.xcievers&lt;/code&gt; to something very large, like 4096.  And yes, the property name is misspelled.  In 0.22/0.23 the property will be called &lt;code&gt;dfs.datanode.max.transfer.threads&lt;/code&gt;.&lt;br /&gt;&lt;li&gt;If you've declared your key type to be T, you can't write an S, even if S is a subclass of T.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There are several ways to get your dependencies visible to Hadoop tasks and tools, and they are all clunky.&lt;ul&gt;&lt;li&gt;You can bundle them all into the job jar in a folder called lib, although doing so does not make it possible to have custom input formats, output formats, mappers, and reducers in separate jars.&lt;/li&gt;&lt;li&gt;You can use the -libjars argument, but if you ever have to load a class via reflection (i.e., using Class.forName), you have to use the Thread.currentThread().getContextClassLoader() rather than the default.  Also you might run into HADOOP-6103.&lt;/li&gt;&lt;li&gt;You can use DistributedCache.addFileToClassPath, but you have to be sure to put the file on HDFS and refer to it by its absolute pathname without a scheme or authority, and these files are only available to the tasks, not the tool/job.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;DistributedCache is just plain wonky.  You must &lt;br /&gt;&lt;ol&gt;&lt;li&gt;put your file on hdfs somehow&lt;/li&gt;&lt;li&gt;call DistributedCache.addCacheFile(), using the full URI with "hdfs:///"&lt;/li&gt;&lt;li&gt;in the mapper/reducer, &lt;em&gt;use java.io.* APIs to access the files represented by the paths in DistributedCache.getLocalCacheFiles()&lt;/em&gt;.  Incredibly, the "typical usage" example in the javadocs for DistributedCache just completely elides this crucial bit.  If you try to use FileSystem.get().open(), you'll get a cryptic error message with a filename that looks like it's been mangled.&lt;br/&gt;I can't find a programmatic mapping between files added via addCacheFile() and paths retrieved by getLocalCacheFiles(), although there may be some support for sharing the name or specifying it with the "hdfs://source#target" syntax.  None of this API is well-documented.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;You can't substitute Hadoop counters for actual aggregation in your reducer, tempting as that might be.  Counters will differ from run to run, even against identical inputs, because of things that vary like speculative execution and task failures.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-2798943421721450535?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/2798943421721450535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=2798943421721450535' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/2798943421721450535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/2798943421721450535'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2010/11/random-notes-on-hadoop.html' title='Random notes on Hadoop'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-5817599273212876292</id><published>2010-10-24T23:50:00.000-07:00</published><updated>2011-11-06T21:30:32.622-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JVM'/><title type='text'>6 10 Things I Hate About Java (or, Scala is the Way and the Light)</title><content type='html'>I've been working with Java quite extensively for about 4 years now, and it has been enjoyable for the most part.  Garbage collection, the JVM, generics, anonymous classes, and superb IDE support have made my life much easier.&lt;br /&gt;&lt;br /&gt;But a few things make me gnash my teeth on a daily basis, and it's funny, but none of them are issues in another JVM language in which I have been dabbling, &lt;a href="http://www.scala-lang.org"&gt;Scala&lt;/a&gt;.  It seems the developers of that language felt my pain as well.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Miserable type inference.&lt;/strong&gt;  Apparently &lt;em&gt;some&lt;/em&gt; of the problems with it are being addressed in &lt;a href="http://openjdk.java.net/projects/coin/"&gt;project coin&lt;/a&gt; for Java 7.  The blue portions of the following code are, to any sane programmer, maddeningly superfluous, but nevertheless strictly required in Java until at least mid-2011:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;List&amp;lt; Integer &amp;gt; li1 = new ArrayList&lt;span style="font-weight: bold; color:#000055;"&gt;&amp;lt; Integer &amp;gt;&lt;/span&gt;();&lt;br /&gt;List&lt;span style="font-weight: bold; color:#000055;"&gt;&amp;lt; Integer &amp;gt;&lt;/span&gt; li2 = Arrays.asList( 1, 2, 3 );&lt;br /&gt;o.processListOfInteger( Arrays.&lt;span style="font-weight: bold; color:#000055;"&gt;&amp;lt; Integer &amp;gt;&lt;/span&gt;asList() );&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Needless to say, equivalent initializations in Scala require no such redundant information.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Generic invariance.&lt;/strong&gt; An example from last week: I'm working on an implementation &lt;code&gt;FrazzleExecutorService&lt;/code&gt; of &lt;code&gt;java.util.concurrent.ScheduledExecutorService&lt;/code&gt; and a refinement &lt;code&gt;FrazzleFuture&amp;lt; T &amp;gt;&lt;/code&gt; of &lt;code&gt;java.util.ScheduledFuture&amp;lt; T &amp;gt;&lt;/code&gt;.  Covariant subtyping lets me get away with returning a &lt;code&gt;FrazzleFuture&amp;lt; T &amp;gt;&lt;/code&gt; from a method like &lt;code&gt;FrazzleExecutorService.submit()&lt;/code&gt; without violating the contract.  But I can't return &lt;code&gt;List&amp;lt; FrazzleFuture&amp;lt; T &amp;gt; &amp;gt;&lt;/code&gt; from &lt;code&gt;FrazzleExecutorService.invokeAll()&lt;/code&gt; because (a) &lt;code&gt;ScheduledExecutorService&lt;/code&gt; would have had to declare the return type to be &lt;code&gt;List&amp;lt; ? extends ScheduledFuture&amp;lt; T &amp;gt; &amp;gt;&lt;/code&gt;; (b) the returned list should have been immutable anyway; (c) generic types like &lt;code&gt;List&amp;lt; T &amp;gt;&lt;/code&gt; are invariant in their parameters.  In Scala, there is a separate mutable and immutable collections hierarchy, and at least in the immutable one, &lt;code&gt;S&lt;/code&gt; &amp;lt;: &lt;code&gt;T&lt;/code&gt; implies &lt;code&gt;List[ S ] &amp;lt;: List[ T ]&lt;/code&gt;, because &lt;code&gt;List&lt;/code&gt; is declared covariant in its parameter.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Collections can't be tersely initialized.&lt;/strong&gt;  Part of the blame is the Collections framework; part of it is the goddamn language.  The following code illustrates, with green text indicating typical verbosity:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;List&lt;span style="font-weight: bold; color:#000055;"&gt;&amp;lt; Integer &amp;gt;&lt;/span&gt; li1 = &lt;span style="font-weight: bold; color:#005500;"&gt;new ArrayList&amp;lt; Integer &amp;gt;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Arrays.asList(&lt;/span&gt; 1, 2, 3 &lt;span style="font-weight: bold; color:#005500;"&gt;)&lt;br /&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;span style="font-weight: bold; color:#005500;"&gt;@SuppressWarnings( "serial" )&lt;/span&gt;&lt;br /&gt;Map&lt;span style="font-weight: bold; color:#000055;"&gt;&amp;lt; String, String &amp;gt;&lt;/span&gt; mss1 = new HashMap&lt;span style="font-weight: bold; color:#000055;"&gt;&amp;lt; String, String &amp;gt;&lt;/span&gt;&lt;span style="font-weight: bold; color:#005500;"&gt;() { {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;put&lt;/span&gt;( "foo", "bar" );&lt;span style="font-weight: bold; color:#005500;"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;put&lt;/span&gt;( "this", "sucks" );&lt;span style="font-weight: bold; color:#005500;"&gt;&lt;br /&gt;} }&lt;/span&gt;;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Turns out the collections literals are also not supported in Scala; you have to type &lt;code&gt;List( 1, 2, 3 )&lt;/code&gt; or &lt;code&gt;Map( "foo" -&gt; "bar", "this" -&gt; "rocks" )&lt;/code&gt;. Excuse me if I mock Java incessantly at this point.  Collection improvements have been postponed until Java 8, scheduled for mid-2012.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Higher-order programming is absurdly verbose.&lt;/strong&gt; Rather than give code samples, I'll just refer you to &lt;a href="http://functionaljava.org/"&gt;these guys&lt;/a&gt; and let you see for yourself how even a library can't save you from massive boilerplate for the simplest things.  And Scala?  Lambda expressions are built-in as syntactic sugar for functional objects, making higher-order code simple, readable, and terse.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Modeling variant types is awkward.&lt;/strong&gt;  You have to choose from among many bad options:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Representation&lt;/th&gt;&lt;th&gt;Interrogation&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;one sparsely-populated class (S + T modeled as S &amp;times; T)&lt;/td&gt;&lt;td&gt;&lt;code&gt;if&lt;/code&gt;-ladders based on comparing to &lt;code&gt;null&lt;/code&gt; (see 8)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;S &amp;times T and an enum of type labels&lt;/td&gt;&lt;td&gt;switch + casting&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a hierarchy&lt;/td&gt;&lt;td&gt;a bunch of &lt;code&gt;isS()&lt;/code&gt; and &lt;code&gt;isT()&lt;/code&gt; methods and casting&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a hierarchy&lt;/td&gt;&lt;td&gt;various casting attempts wrapped with &lt;code&gt;ClassCastException&lt;/code&gt; catch blocks (ok, that's not really an option, but I get that as an answer in interviews sometimes)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a hierarchy&lt;/td&gt;&lt;td&gt;&lt;code&gt;if&lt;/code&gt;-ladders based on &lt;code&gt;instanceof&lt;/code&gt; and casting&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a hierarchy&lt;/td&gt;&lt;td&gt;polymorphic decomposition and the inevitable bloated APIs at the base class that result&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a hierarchy that includes Visitor&lt;/td&gt;&lt;td&gt;painfully verbose visitors (see 4 and 10)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a hierarchy of &lt;code&gt;Throwable&lt;/code&gt;s&lt;/td&gt;&lt;td&gt;throw and various &lt;code&gt;catch&lt;/code&gt; blocks, which I suspect compiles to the same thing as the instanceof approach, only more expensive (but actually requires the least code!)&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;Scala has &lt;a href="http://www.scala-lang.org/node/107"&gt;case classes&lt;/a&gt; and &lt;a href="http://www.scala-lang.org/node/120"&gt;pattern matching&lt;/a&gt; built in.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;No tuples.&lt;/strong&gt; One ends up either creating &lt;code&gt;Pair&amp;lt; S, T &amp;gt;&lt;/code&gt; or dozens of throwaway classes with "And" in the name, like &lt;code&gt;CountAndElapsed&lt;/code&gt;.  Scala has tuples, although I feel like they kind of screwed up by not going the full ML and making multi-argument functions/methods be the same as single-argument functions/methods over tuples.  So to call a 2-arg function &lt;code&gt;f&lt;/code&gt; with a pair &lt;code&gt;p = ( p1, p2 )&lt;/code&gt;, you can either call &lt;code&gt;f( p1, p2 )&lt;/code&gt; or &lt;code&gt;f.tupled( p )&lt;/code&gt;.  There must be some deep reason for making the distinction.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;No mixins.&lt;/strong&gt;  If you need stuff from 2 abstract classes, you will be copying, or aggregating (with loads of monkey delegation boilerplate) at least one of the two.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Null.&lt;/strong&gt; The following code should illustrate:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;private static Doohickey getDoohickey( Thingamajigger t ) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Whatsit w;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Foobar f;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( null == t )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else if ( null == ( w = t.getWhatsit() ) )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else if ( null == ( f = w.getFoobar() ) )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return null;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return f.getDoohickey();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;I believe the "&lt;a href="http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html"&gt;Elvis&lt;/a&gt;" operator was developed to solve this annoyance (&lt;code&gt;return t.?getWhatsit().?getFoobar().?getDoohickey();&lt;/code&gt;) but it did not make the cut for Java 7 or even Java 8, from what I understand.  Scala's solution to this issue is to recommend that operations which might not have a value for you return &lt;code&gt;Option[ T ]&lt;/code&gt; instead of &lt;code&gt;T&lt;/code&gt;.  You can then map your method call to the Option and get back another Option without ever seeing a null pointer exception.  Option is a variant type, easily modeled in Scala but not in Java (see 5).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Iterators&lt;/strong&gt;.  They can't throw checked exceptions.  They have to implement &lt;code&gt;remove()&lt;/code&gt;, often by throwing (unchecked) &lt;code&gt;UnsupportedOperationException&lt;/code&gt;s.  For-each syntax can't work with iterators directly.  None of these problems arise with the superb &lt;a href="http://www.scala-lang.org/docu/files/collections-api/collections.html"&gt;collections framework&lt;/a&gt; in Scala which is designed hand-in-hand with its clean higher-order programming (see 4).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;void&lt;/code&gt;&lt;/strong&gt;.  This is a holdover from C, and is obviously not anything Java can get rid of, but it's stupid.  Because of &lt;code&gt;void&lt;/code&gt;, &lt;i&gt;e.g.&lt;/i&gt;, I can never do a &lt;a href="http://www.dofactory.com/Patterns/PatternVisitor.aspx"&gt;visitor pattern&lt;/a&gt; with just one kind of visitor; there has to be one whose methods return a generic type T, and another whose methods return &lt;code&gt;void&lt;/code&gt;.  And don't try to sell me on the psuedo-type &lt;code&gt;Void&lt;/code&gt;, because you still have to accept or return &lt;code&gt;null&lt;/code&gt; somewhere.  Scala has a type &lt;code&gt;Unit&lt;/code&gt; with a single trivial value &lt;code&gt;()&lt;/code&gt;, and unitary methods/functions can explicitly return that value or not return anything; the semantics are the same.  Thus all expressions have some meaningful type, and classes with generic types can be fully general.&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-5817599273212876292?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/5817599273212876292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=5817599273212876292' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/5817599273212876292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/5817599273212876292'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html' title='&lt;strike&gt;6&lt;/strike&gt; &lt;strong&gt;10&lt;/strong&gt; Things I Hate About Java (or, Scala is the Way and the Light)'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-4517751483853373124</id><published>2010-04-07T17:44:00.000-07:00</published><updated>2010-10-20T22:23:37.472-07:00</updated><title type='text'>Why tabs are better</title><content type='html'>I'm tired of this stupid "tabs vs. spaces" code style debate.  Tabs win hands down on just about every measure.  Anyone still laboring under the misapprehension that it makes sense to indent one's source file using spaces should consider the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Line-based comments&lt;/b&gt; (‘//’, ‘#’) at the head of the line don’t screw up the indentation (unless tab depth &amp;lt;= 2).&lt;/li&gt;&lt;li&gt;&lt;b&gt;You can change the indentation depth&lt;/b&gt; without editing the file.  This is a huge feature, folks.  If I like shallow indentation on all my source, I can make it so, and people who prefer the other extreme are not affected.  The counter-argument (put forth by &lt;a href="http://checkstyle.sourceforge.net/config_whitespace.html#FileTabCharacter"&gt;Checkstyle&lt;/a&gt;, among others) that one should not be required to set tab depth in order to read source is absurd; tab depth is always set to something, whether you like it or not (see 11), and code indented using tabs is readable regardless of the setting, unless tab depth is ridiculously high.  The only code that actually does require a fixed tab depth to be legible is code that &lt;i&gt;mixes&lt;/i&gt; tabs and spaces, which I encounter all too often.  See 10.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Spaces-based indentation will inevitably become inconsistent&lt;/b&gt; because no one can agree on his/her favorite indentation depth (see 2).&lt;/li&gt;&lt;li&gt;&lt;b&gt;Indentation mistakes are more obvious&lt;/b&gt; using tabs (unless tab depth = 1, which is just stupid).&lt;/li&gt;&lt;li&gt;Tab indentation characters, when used properly, are &lt;b&gt;more semantically relevant&lt;/b&gt; than spaces.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Files are smaller&lt;/b&gt; (relevant especially for Javascript, CSS, HTML).&lt;/li&gt;&lt;li&gt;&lt;b&gt;Fewer keystrokes&lt;/b&gt; are needed to navigate within source files.  Sorry, but “Ctrl+Right arrow” is two keystrokes, plus you have to hold one of them down.&lt;/li&gt;&lt;li&gt;Making tabbed whitespace visible in an IDE is useful for &lt;b&gt;eyeballing how things line up&lt;/b&gt;; making spaces visible is useful for &lt;a href="http://www.magiceye.com"&gt;“magic eye”&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Tabs are unable to support the unreadable, but nevertheless default, function-call &lt;b&gt;line-break style&lt;/b&gt; of making parameters line up with the opening ‘(’.  Remember, it is a &lt;i&gt;feature&lt;/i&gt; that this abomination is not supportable.  Unfortunately it is still possible to put just the first parameter on the same line as the ‘(’, but no indentation choice can prevent that bad decision.&lt;/li&gt;&lt;li&gt;If you have to edit a production config file using terminal-based default emacs, should you really be checking that in?   I should add that the indentation used by default in Emacs (and pervasive in high-profile source such as the JDK) is a horrific hybrid of spaces and tabs which actually does force you to set your tab depth to a fixed value of 8 in order to read code thus indented.  See 2.&lt;/li&gt;&lt;li&gt;Some well-known tools (e.g., &lt;a href="http://www.reviewboard.org"&gt;ReviewBoard&lt;/a&gt;) typically display tabs with a depth of 8, which is kind of high.  I claim that this tab discrimination is also a feature, because it &lt;b&gt;discourages deeply-nested code&lt;/b&gt; which is a good thing.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;The only moderately sane argument in favor of spaces is that the code "always looks the same".  Isn't that nice.  You can write comments that use little "^^^^" to point to something on the line above.  Wow.  I guess that's worth throwing out points 1-11.&lt;br /&gt;&lt;br /&gt;I'm not going to wade into the quagmire of my other personal code style choices.  But it's time this debate, which rages again and again every time I join a new team, be permanently put to bed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-4517751483853373124?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/4517751483853373124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=4517751483853373124' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/4517751483853373124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/4517751483853373124'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2010/04/why-tabs-are-better.html' title='Why tabs are better'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-3273260078162989032</id><published>2009-06-25T13:44:00.000-07:00</published><updated>2012-01-24T20:53:11.076-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JAXB'/><category scheme='http://www.blogger.com/atom/ns#' term='mixed content'/><title type='text'>JAXB, @XmlMixed, and white space anomalies</title><content type='html'>&lt;p&gt;Whether or not you think "mixed" content in XML is ever a good idea, you may need to handle it using JAXB one day.  Recall that for JAXB to parse a mixed content XML element to a class C, you use an &lt;code&gt;@XmlMixed&lt;/code&gt; annotation on a field of C of type &lt;code&gt;List&amp;lt; Serializable &amp;gt;&lt;/code&gt;, combined with either &lt;code&gt;@XmlAnyElement&lt;/code&gt; or &lt;code&gt;@XmlElements&lt;/code&gt;.  In each case, the resulting list will contain Strings representing the text nodes and objects representing the element nodes, in the same order as they appear in the XML text.  Thus&lt;pre&gt;&lt;br /&gt;&amp;lt;thing&amp;gt;stuff&amp;lt;nested/&amp;gt;entities&amp;lt;alsoNested/&amp;gt;&amp;lt;/thing&amp;gt;&lt;br /&gt;&lt;/pre&gt;maps to an instance of&lt;pre&gt;&lt;br /&gt;@XmlRootElement&lt;br /&gt;class Thing {&lt;br /&gt;    @XmlMixed @XmlAnyElement&lt;br /&gt;    List&amp;lt; Serializable &amp;gt; lserComponents;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;which looks like&lt;pre&gt;&lt;br /&gt;{ lserComponents : [ "stuff", { localName : "nested" }, "entities", { localName: "alsoNested" } ] }&lt;br /&gt;&lt;/pre&gt;Unfortunately, if the only content other than nested elements happens to be white space, as in&lt;pre&gt;&lt;br /&gt;&amp;lt;thing&amp;gt;&amp;lt;nested/&amp;gt;   &amp;lt;alsoNested/&amp;gt;&amp;lt;/thing&amp;gt;&lt;br /&gt;&lt;/pre&gt;you get the odd bound object&lt;pre&gt;&lt;br /&gt;{ lserComponents : [ { localName : "nested" }, { localName: "alsoNested" }, "" ] }&lt;br /&gt;&lt;/pre&gt;If you care about white space, and who doesn't these days in the throes of  late-stage Reaganomics, you need a trick when you actually go to parse the XML.&lt;/p&gt;&lt;p&gt;First, we create a SAX 2.0 ContentHandler implementation that delegates all events to a JAXB UnmarshallerHandler, but modifies all the whitespace slightly:&lt;pre&gt;&lt;br /&gt;class WhitespaceAwareUnmarshallerHandler implements ContentHandler {&lt;br /&gt;  private final UnmarshallerHandler uh;&lt;br /&gt;  public WhitespaceAwareUnmarshallerHandler( UnmarshallerHandler uh ) {&lt;br /&gt;    this.uh = uh;&lt;br /&gt;  }&lt;br /&gt;  /**&lt;br /&gt;   * Replace all-whitespace character blocks with the character '\u000B',&lt;br /&gt;   * which satisfies the following properties:&lt;br /&gt;   * &lt;br /&gt;   * 1. "\u000B".matches( "\\s" ) == true&lt;br /&gt;   * 2. when parsing XmlMixed content, JAXB does not suppress the whitespace&lt;br /&gt;   **/&lt;br /&gt;  public void characters(&lt;br /&gt;    char[] ch, int start, int length&lt;br /&gt;  ) throws SAXException {&lt;br /&gt;    for ( int i = start + length - 1; i &amp;gt;= start; --i )&lt;br /&gt;      if ( !Character.isWhitespace( ch[ i ] ) ) {&lt;br /&gt;        uh.characters( ch, start, length );&lt;br /&gt;        return;&lt;br /&gt;      }&lt;br /&gt;    Arrays.fill( ch, start, start + length, '\u000B' );&lt;br /&gt;    uh.characters( ch, start, length );&lt;br /&gt;  }&lt;br /&gt;  /* what follows is just blind delegation monkey code */&lt;br /&gt;  public void ignorableWhitespace( char[] ch, int start, int length ) throws SAXException { uh.characters( ch, start, length ); }&lt;br /&gt;  public void endDocument() throws SAXException { uh.endDocument(); }&lt;br /&gt;  public void endElement( String uri, String localName, String name ) throws SAXException { uh.endElement( uri,  localName, name ); }&lt;br /&gt;  public void endPrefixMapping( String prefix ) throws SAXException { uh.endPrefixMapping( prefix ); }&lt;br /&gt;  public void processingInstruction( String target, String data ) throws SAXException { uh.processingInstruction(  target, data ); }&lt;br /&gt;  public void setDocumentLocator( Locator locator ) { uh.setDocumentLocator( locator ); }&lt;br /&gt;  public void skippedEntity( String name ) throws SAXException { uh.skippedEntity( name ); }&lt;br /&gt;  public void startDocument() throws SAXException { uh.startDocument(); }&lt;br /&gt;  public void startElement( String uri, String localName, String name, Attributes atts ) throws SAXException { uh.startElement( uri, localName, name, atts ); }&lt;br /&gt;  public void startPrefixMapping( String prefix, String uri ) throws SAXException { uh.startPrefixMapping( prefix, uri ); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Then at parse time, instead of the usual &lt;code&gt;ctx.createUnmarhaller().unmarshal( strData )&lt;/code&gt;, we substitute our special handler to do the parsing:&lt;pre&gt;&lt;br /&gt;public class JAXBUtil {&lt;br /&gt;  @SuppressWarnings( "unchecked" )&lt;br /&gt;  public static &amp;lt; T &amp;gt; T unmarshal(&lt;br /&gt;    JAXBContext ctx, String strData, boolean flgWhitespaceAware&lt;br /&gt;  ) throws Exception {&lt;br /&gt;    UnmarshallerHandler uh = ctx.createUnmarshaller().getUnmarshallerHandler();&lt;br /&gt;    XMLReader xr = new WstxSAXParser(); // use your favorite SAX 2.0 parser&lt;br /&gt;    xr.setContentHandler( flgWhitespaceAware ? new WhitespaceAwareUnmarshallerHandler( uh ) : uh );&lt;br /&gt;    xr.parse( new InputSource( new StringReader( strData ) ) );&lt;br /&gt;    return ( T )uh.getResult();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-3273260078162989032?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/3273260078162989032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=3273260078162989032' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/3273260078162989032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/3273260078162989032'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2009/06/jaxb-xmlmixed-and-white-space-anomalies.html' title='JAXB, @XmlMixed, and white space anomalies'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-5239075381920698424</id><published>2008-05-15T17:16:00.000-07:00</published><updated>2008-05-15T17:22:14.135-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='XSLT'/><title type='text'>Identity transformation, my butt</title><content type='html'>Some lovely trivia I have recently discovered about the default implementations of XSLT transformations in the JDK 1.5:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;The so-called "identity transformation" available at &lt;code&gt;TransformerFactory.newTransformer()&lt;/code&gt; is anything but the identity when applied to XHTML, until certain non-default configuration is applied.  Specifically, you have to do all this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  xfmEng.setOutputProperty( OutputKeys.DOCTYPE_SYSTEM, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" );&lt;br /&gt;  xfmEng.setOutputProperty( OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD XHTML 1.0 Transitional//EN" );&lt;br /&gt;  xfmEng.setOutputProperty( OutputKeys.METHOD, "html" );&lt;br /&gt;  xfmEng.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or you get tons of &lt;code&gt;&amp;lt;!-- ... --&amp;gt;&lt;/code&gt; garbage before the real document.  The garbage seems to live in the w3c.org dtd files for xhtml.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Even with all that, you still end up with the very non-identity transformation of input like &lt;code&gt;&amp;lt;script src=...&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; becoming &lt;code&gt;&amp;lt;script src=.../&amp;gt;&lt;/code&gt;.  The latter is actually malformed according to many browsers.  Forget newTransformer() and use an xslt-based transformation like&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;&lt;br /&gt; &amp;lt;xsl:output method="html"/&amp;gt;&lt;br /&gt; &amp;lt;xsl:template match="/"&amp;gt;&lt;br /&gt;  &amp;lt;xsl:copy-of select="."/&amp;gt;&lt;br /&gt; &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;&amp;lt;/xsl:stylesheet&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Speaking of the w3c.org dtd files, there's still some nasty stuff going on behind the scenes; when any transformer created via &lt;code&gt;TransformerFactory.newTransformer()&lt;/code&gt; or &lt;code&gt;Templates.newTransformer()&lt;/code&gt; starts processing XHTML, it actually goes and grabs those extremely well-known DTDs off the web from their URIs at w3c.org.  Every document, even with the same transformer, engenders a new set of GETs to w3c.  Pretty ridiculous.  Here's how to get around that:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package MyPackage;&lt;br /&gt;&lt;br /&gt;import org.xml.sax.SAXNotRecognizedException;&lt;br /&gt;import org.xml.sax.SAXNotSupportedException;&lt;br /&gt;import com.sun.org.apache.xerces.internal.impl.Constants;&lt;br /&gt;import com.sun.org.apache.xerces.internal.parsers.SAXParser;&lt;br /&gt;&lt;br /&gt;public class MyTransform {&lt;br /&gt;&lt;br /&gt; // ...&lt;br /&gt;&lt;br /&gt; public static class MySAXParser extends SAXParser {&lt;br /&gt;  public MySAXParser() {&lt;br /&gt;   super();&lt;br /&gt;   try {&lt;br /&gt;    setFeature( Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE, false );&lt;br /&gt;    setFeature( Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE, false );&lt;br /&gt;   } catch ( SAXNotRecognizedException sne ) {&lt;br /&gt;   } catch ( SAXNotSupportedException sse ) {&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // in the code that uses the transformer:&lt;br /&gt;  System.setProperty( "org.xml.sax.driver", "MyPackage.MyTransform$MySAXParser" );&lt;br /&gt;  TransformerFactory.newInstance().newTransformer().transform( stmIn, stmOut );&lt;br /&gt;&lt;br /&gt; // ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-5239075381920698424?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/5239075381920698424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=5239075381920698424' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/5239075381920698424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/5239075381920698424'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2008/05/identity-transformation-my-butt.html' title='Identity transformation, my butt'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-5617922417787235413</id><published>2008-05-15T17:14:00.000-07:00</published><updated>2008-05-19T14:25:58.066-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AspectJ'/><title type='text'>AspectJ: A crucial distinction between execution and call join points</title><content type='html'>Given the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  class Super {&lt;br /&gt;    protected void m() {}&lt;br /&gt;  }&lt;br /&gt;  class Sub extends Super {}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A call( * Sub+.m( .. ) ) join point will match any call to m made on an instance statically known to be a Sub (in particular, ( ( Super )s ).m() will not only not match, but will cause a compiler warning); an execution( * Sub+.m() ) join point will not match s.m(), even if s is Sub, because there's no m() code to execute in Sub!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-5617922417787235413?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/5617922417787235413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=5617922417787235413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/5617922417787235413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/5617922417787235413'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2008/05/aspectj-crucial-distinction-between.html' title='AspectJ: A crucial distinction between execution and call join points'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-2438460696021782935</id><published>2008-05-15T13:01:00.000-07:00</published><updated>2008-06-26T15:38:40.876-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AspectJ'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Transactions'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring declarative transactions, applied dynamically</title><content type='html'>I think declarative transaction management is possibly the most compelling reason for using the Spring Framework.  I won't explain how it usually works, leaving that to the Spring docs and plenty of examples in the literature.  Recently I ran into the following conundrum, however.&lt;br /&gt;&lt;br /&gt;I have a service class that has not only some "transactional" methods, but also other methods that return instances of secondary classes with their own transactional methods.  It is easy in the configuration of the Spring container to declare the transactional methods in the service as such, because it is a typical singleton bean.  The problem is that if the code in the service implementation is to remain decoupled from Spring, how do we instruct Spring to wrap transactional proxies around any instances of the secondary classes that are produced at runtime?&lt;br /&gt;&lt;br /&gt;My first attempt to solve this problem was to factor the code that needed to be transactional out of the secondary classes into package-access methods on the main service, in the hopes that I could declare those helper methods transactional in the configuration.  Then the formerly transactional methods in the secondary classes could call those helper methods back in the service bean.  This attempt proved to be not just inelegant, but also ineffectual: a complete waste of time.&lt;br /&gt;&lt;br /&gt;Why didn't it work?  Because the newly-minted secondary class instances were not receiving a reference to the service bean's &lt;i&gt;transactional proxy&lt;/i&gt; to make their call backs on; they got the unadorned service instance as obtained via &lt;b&gt;this&lt;/b&gt;, and in order to get the proxy, the Spring coupling would have to creep back into the code.  Only a more complete AOP framework like AspectJ, with its special compiler, could avoid the &lt;b&gt;this&lt;/b&gt; problem.&lt;br /&gt;&lt;br /&gt;My solution to this problem was in four parts.  Spring 2.5 is required.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Create a new implementation of each secondary class which is a pure delegating proxy.  The constructor of DelegatingSecondaryClassImpl takes a SecondaryClass as delegate, and every method simply forwards to that delegate.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Create a BeanFactoryAware aspect ServiceAdvice with around advice for the methods on the service class that produce instances of these secondary classes, one advice method per secondary class.  In each case the advice looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public SecondaryClass secondaryClassAroundAdvice( ProceedingJoinPoint pjp ) throws Throwable {&lt;br /&gt;  return ( SecondaryClass )bf.getBean( "secondaryClassBeanId", new Object[] { pjp.proceed() } );&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Add a prototype bean to the configuration XML for each secondary class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &amp;lt;bean id="secondaryClassBeanId" class="com.amazon.foo.bar.DelegatingSecondaryClassImpl" scope="prototype"&amp;gt;&lt;br /&gt;  &amp;lt;constructor-arg&amp;gt;&amp;lt;null/&amp;gt;&amp;lt;/constructor-arg&amp;gt;&lt;br /&gt; &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Add advice to the service methods that produce instances of each secondary class in the configuration XML:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &amp;lt;bean id="serviceAdvice" class="com.amazon.foo.bar.ServiceAdvice"&amp;gt;&lt;br /&gt; &amp;lt;aop:config&amp;gt;&lt;br /&gt;  &amp;lt;!-- transactional advisor goes here ... --&amp;gt;&lt;br /&gt;  &amp;lt;aop:aspect id="proxyAspect" ref="proxyAdvice"&amp;gt;&lt;br /&gt;   &amp;lt;aop:around pointcut="execution( com.amazon.foo.bar.SecondaryClass createSecondaryClass1( .. ) ) || execution( com.amazon.foo.bar.SecondaryClass createSecondaryClass2( .. ) )" method="secondaryClassAroundAdvice"&amp;gt;&lt;br /&gt;   &amp;lt;/aop:around&amp;gt;&lt;br /&gt;  &amp;lt;/aop:aspect&amp;gt;&lt;br /&gt; &amp;lt;/aop:config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-2438460696021782935?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/2438460696021782935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=2438460696021782935' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/2438460696021782935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/2438460696021782935'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2008/05/spring-declarative-transactions-applied.html' title='Spring declarative transactions, applied dynamically'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-1708731916611917121</id><published>2007-08-03T21:56:00.000-07:00</published><updated>2012-01-05T02:41:11.655-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AspectJ'/><category scheme='http://www.blogger.com/atom/ns#' term='Lazy loading'/><title type='text'>AspectJ for lazy loading, improved</title><content type='html'>&lt;p&gt;I find Russ Miles' lazy feature loading recipe (&lt;a href="http://www.amazon.com/AspectJ-Cookbook-Russell-Miles/dp/0596006543/"&gt;AspectJ Cookbook&lt;/a&gt;, chapter 21.3) cumbersome and at odds with the whole point of AOP. You have to use joinPoint.getArgs inside a proxy; but you're using AspectJ instead of Spring to avoid the proxy-based Spring AOP implementation, with all its intrinsic problems (what does "&lt;code&gt;this&lt;/code&gt;" mean?).  You also have to be aware in the mainline code that you're doing lazy loading and explicitly call LazyLoading.aspectOf().initializeFeature(), so it's intrusive.&lt;/p&gt;&lt;p&gt;In addition, there is essentially no reusability here.  You have to create a special aspect for each interface which you wish to load lazily, with stubs for every method of that interface.&lt;/p&gt;&lt;p&gt;Finally, you have to use a weird trick of declaring that one interface implements another without actually giving any implementation (this line is given with no explanation in the text).&lt;/p&gt;&lt;p&gt;My approach, by contrast, is extremely simple.  I do still impose a burden on the mainline code; specifically, if you want to see any benefit from lazy loading of an object you have to make sure the expensive initialization code actually occurs within the construction of that object.  But that's it.  No proxies, no hard-coded interface stubs, no intrusion.&lt;/p&gt;&lt;p&gt;The basic technique is to suppress the execution of the object's initialization code, wrapping it in a closure and storing it away until the first access to the object that requires that the initialization take place.  The storage of the closure, and the state of the flag indicating that the initialization has or has not been attempted, live inside a small pertarget aspect.&lt;/p&gt;&lt;p&gt;Here's two variations of the LazyInitialization aspect.&lt;/p&gt;&lt;p&gt;The first:&lt;/p&gt;&lt;pre&gt;&lt;span style="color: #33cc00;"&gt;// one aspect instance per lazily-instantiated object&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #990000;"&gt;public aspect&lt;/span&gt; LazyInitialization &lt;span style="color: #990000;"&gt;pertarget&lt;/span&gt;( &lt;span style="color: #990000;"&gt;target&lt;/span&gt;( Lazy ) ) {&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt;// this interface represents a closure for the real initialization&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #990000;"&gt;private interface&lt;/span&gt; DelayedInit {&lt;br /&gt; &lt;span style="color: #990000;"&gt;void &lt;/span&gt;init();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt;// this is the marker interface for types that should be&lt;br /&gt;// lazily initialized&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #990000;"&gt;public interface&lt;/span&gt; Lazy {};&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt; // per-object aspect state&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #990000;"&gt; boolean &lt;/span&gt;flgTried = &lt;span style="color: #990000;"&gt;false&lt;/span&gt;;&lt;br /&gt; DelayedInit fnInit = &lt;span style="color: #990000;"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt; // this advice intercepts the normal initialization process for&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt; // a Lazy object and stashes a closure for it in the aspect&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #990000;"&gt; void around&lt;/span&gt;() : &lt;span style="color: #990000;"&gt;execution&lt;/span&gt;( Lazy+.&lt;span style="color: #990000;"&gt;new&lt;/span&gt;( .. ) ) {&lt;br /&gt;  &lt;span style="color: #990000;"&gt;synchronized&lt;/span&gt;( &lt;span style="color: #990000;"&gt;this &lt;/span&gt;) {&lt;br /&gt;   &lt;span style="color: #990000;"&gt;if &lt;/span&gt;( fnInit == null )&lt;br /&gt;    fnInit = &lt;span style="color: #990000;"&gt;new &lt;/span&gt;DelayedInit() {&lt;br /&gt;     &lt;span style="color: #990000;"&gt;public void &lt;/span&gt;init() {&lt;br /&gt;      &lt;span style="color: #990000;"&gt;proceed&lt;/span&gt;();&lt;br /&gt;     }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt;  // this advice intercepts any access to a Lazy object that might&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #33cc00;"&gt;  // require it to actually initialize, and does so if necessary&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #990000;"&gt;before&lt;/span&gt;() : &lt;span style="color: #990000;"&gt;call&lt;/span&gt;( * Lazy+.*( .. ) ) || &lt;span style="color: #990000;"&gt;get&lt;/span&gt;( * Lazy+.* ) || &lt;span style="color: #990000;"&gt;set&lt;/span&gt;( * Lazy+.* ) {&lt;br /&gt;   &lt;span style="color: #990000;"&gt;synchronized&lt;/span&gt;( this ) {&lt;br /&gt;    &lt;span style="color: #990000;"&gt;if &lt;/span&gt;( !flgTried ) {&lt;br /&gt;     flgTried = true;&lt;br /&gt;     fnInit.init();&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;To use it, just declare somewhere that some class or interface C implements LazyInitialization.Lazy and every instance of C or its subclasses/implementations will be lazily initialized:&lt;/p&gt;&lt;pre&gt;&lt;span style="color: #990000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: #990000;"&gt;aspect&lt;/span&gt; MakeCLazy {&lt;br /&gt;   &lt;span style="color: #990000;"&gt;declare parents&lt;/span&gt; : C+ &lt;span style="color: #990000;"&gt;implements&lt;/span&gt; LazyInitialization.Lazy;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The other variation uses a generic type variable T instead of a marker interface.  This version allows you to be more specific about which classes/interfaces/methods are to be lazily initialized and what constitutes an initialization-worthy access via filter pointcuts.&lt;/p&gt;&lt;pre&gt;&lt;span style="color: #990000;"&gt;public abstract aspect&lt;/span&gt; GenericLazyInit&amp;lt; T &amp;gt; &lt;span style="color: #990000;"&gt;pertarget&lt;/span&gt;( initFilter() ) {&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #33cc00;"&gt;// this interface represents a closure for the real initialization&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #990000;"&gt;private interface&lt;/span&gt; DelayedInit {&lt;br /&gt;  &lt;span style="color: #990000;"&gt;void&lt;/span&gt; init();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #33cc00;"&gt;// per-object aspect state&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #990000;"&gt;boolean&lt;/span&gt; flgTried = &lt;span style="color: #990000;"&gt;false&lt;/span&gt;;&lt;br /&gt; DelayedInit fnInit = &lt;span style="color: #990000;"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #990000;"&gt;protected pointcut&lt;/span&gt; initFilter() : &lt;span style="color: #990000;"&gt;execution&lt;/span&gt;( T+.&lt;span style="color: #990000;"&gt;new&lt;/span&gt;( .. ) );&lt;br /&gt; &lt;span style="color: #990000;"&gt;protected pointcut&lt;/span&gt; accessFilter() : &lt;span style="color: #990000;"&gt;call&lt;/span&gt;( * T+.*( .. ) ) || &lt;span style="color: #990000;"&gt;get&lt;/span&gt;( * T+.* ) || &lt;span style="color: #990000;"&gt;set&lt;/span&gt;( * T+.* );&lt;br /&gt; &lt;br /&gt; &lt;span style="color: #33cc00;"&gt;// this advice intercepts the normal initialization process for&lt;br /&gt; // a Lazy object and stashes a closure for it in the aspect&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #990000;"&gt;void around&lt;/span&gt;() : initFilter() {&lt;br /&gt;  &lt;span style="color: #990000;"&gt;synchronized&lt;/span&gt;( &lt;span style="color: #990000;"&gt;this&lt;/span&gt; ) {&lt;br /&gt;   &lt;span style="color: #990000;"&gt;if&lt;/span&gt; ( fnInit == &lt;span style="color: #990000;"&gt;null&lt;/span&gt; )&lt;br /&gt;    fnInit = &lt;span style="color: #990000;"&gt;new&lt;/span&gt; DelayedInit() {&lt;br /&gt;     &lt;span style="color: #990000;"&gt;public void&lt;/span&gt; init() {&lt;br /&gt;      &lt;span style="color: #990000;"&gt;proceed&lt;/span&gt;();&lt;br /&gt;     }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #33cc00;"&gt;// this advice intercepts any access to a Lazy object that might&lt;br /&gt; // require it to actually initialize, and does so if necessary&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #990000;"&gt;before&lt;/span&gt;() : accessFilter() {&lt;br /&gt;  &lt;span style="color: #990000;"&gt;synchronized&lt;/span&gt;( &lt;span style="color: #990000;"&gt;this&lt;/span&gt; ) {&lt;br /&gt;   &lt;span style="color: #990000;"&gt;if&lt;/span&gt; ( !flgTried &amp;amp;&amp;amp; fnInit != &lt;span style="color: #990000;"&gt;null&lt;/span&gt; ) {&lt;br /&gt;    flgTried = &lt;span style="color: #990000;"&gt;true&lt;/span&gt;;&lt;br /&gt;    fnInit.init();&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Using this version (in its default configuration, equivalent to variation 1) is even briefer:&lt;/p&gt;&lt;pre&gt;&lt;span style="color: #990000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="color: #990000;"&gt;aspect&lt;/span&gt; MakeCLazy &lt;span style="color: #990000;"&gt;extends&lt;/span&gt; GenericLazyInit&amp;lt; C &amp;gt; {}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-1708731916611917121?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/1708731916611917121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=1708731916611917121' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/1708731916611917121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/1708731916611917121'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2007/08/aspectj-for-lazy-loading-improved.html' title='AspectJ for lazy loading, improved'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-116178605370230848</id><published>2006-10-25T07:19:00.000-07:00</published><updated>2006-10-25T07:20:53.716-07:00</updated><title type='text'>Just in case you hadn't read about the Republicans who are running for congress in 2 weeks</title><content type='html'>Here they are:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.phoenixnewtimes.com/Issues/2006-04-13/news/feature_full.html"&gt;Jon Kyl&lt;/a&gt; &lt;a href="http://en.wikipedia.org/w/index.php?title=Rick_Renzi&amp;printable=yes#Controversies"&gt;Rick Renzi&lt;/a&gt; &lt;a href="http://www.azcentral.com/arizonarepublic/local/articles/1022hayworth1022.html"&gt;J.D. Hayworth&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/John_Doolittle#Controversies"&gt;John Doolittle&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Richard_Pombo#Controversies_and_criticisms"&gt;Richard Pombo&lt;/a&gt; &lt;a href="http://www.kfmb.com/story.php?id=66505"&gt;Brian Bilbray&lt;/a&gt; &lt;a href="http://www.rollingstone.com/politics/story/12054520/the_10_worst_congressmen/10"&gt;Marilyn Musgrave&lt;/a&gt; &lt;a href="http://www.gazette.com/display.php?id=1322626&amp;amp;amp;secid=1"&gt;Doug Lamborn&lt;/a&gt; &lt;a href="http://www.rockymountainnews.com/drmn/elections/article/0,2808,DRMN_24736_5063243,00.html"&gt;Rick O'Donnell&lt;/a&gt; &lt;a href="http://www.connpost.com/news/ci_4509567"&gt;Christopher Shays&lt;/a&gt; &lt;a href="http://www.bradenton.com/mld/bradenton/news/local/15422371.htm?source=rss&amp;amp;channel=bradenton_local"&gt;Vernon Buchanan&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Mark_Foley_scandal"&gt;Joe Negron&lt;/a&gt; &lt;a href="http://www.usnews.com/usnews/politics/campaign_diary/florida/archive/2006/10/the_foley_scandal_affects_the.htm"&gt;Clay Shaw&lt;/a&gt; &lt;a href="http://www.summitdaily.com/article/20060923/NEWS/60923003"&gt;Bill Sali&lt;/a&gt; &lt;a href="http://msnbc.msn.com/id/14988252/"&gt;Peter Roskam&lt;/a&gt; &lt;a href="http://cbs2chicago.com/video/?id=25835@wbbm.dayport.com"&gt;Mark Kirk&lt;/a&gt; &lt;a href="http://www.kcci.com/politics/10062284/detail.html"&gt;Dennis Hastert&lt;/a&gt; &lt;a href="http://www.southbendtribune.com/apps/pbcs.dll/article?AID=/20060811/NEWS07/608110314"&gt;Chris Chocola&lt;/a&gt; &lt;a href="http://www.courier-journal.com/localnews/2004/04/21ky/B1-host0421i0-7412.html"&gt;John Hostettler&lt;/a&gt; &lt;a href="http://www.qctimes.net/articles/2005/12/09/news/local/doc439930283db6c088625962.txt"&gt;Mike Whalen&lt;/a&gt; &lt;a href="http://cjonline.com/stories/102306/loc_ryunboyda1.shtml"&gt;Jim Ryun&lt;/a&gt; &lt;a href="http://www.courier-journal.com/localnews/2002/08/29/ke082902s267079.htm"&gt;Anne Northup&lt;/a&gt; &lt;a href="http://www.kentucky.com/mld/kentucky/news/15533221.htm"&gt;Geoff Davis&lt;/a&gt; &lt;a href="http://www.gazette.net/stories/021006/montsta130223_31925.shtml"&gt;Michael Steele&lt;/a&gt; &lt;a href="http://www.hometown-pages.com/main.asp?SectionID=26&amp;SubSectionID=186&amp;amp;ArticleID=12951&amp;TM=48834.09"&gt;Gil Gutknecht&lt;/a&gt; &lt;a href="http://citypages.com/databank/27/1348/article14760.asp"&gt;Michele Bachmann&lt;/a&gt; &lt;a href="http://www.contracostatimes.com/mld/cctimes/news/politics/15174500.htm"&gt;Jim Talent&lt;/a&gt; &lt;a href="http://www.billingsgazette.net/articles/2006/07/28/news/state/20-burns.txt"&gt;Conrad Burns&lt;/a&gt; &lt;a href="http://www.lasvegassun.com/sunbin/stories/sun/2006/oct/22/566689009.html?porter"&gt;Jon Porter&lt;/a&gt; &lt;a href="http://www.unionleader.com/article.aspx?headline=Top+aide+to+Bass+resigns&amp;amp;amp;articleId=b65bcd02-f478-4a6d-801a-9a12761c3786"&gt;Charlie Bass&lt;/a&gt; &lt;a href="http://www.washingtonpost.com/ac2/wp-dyn/A23714-2003Apr3?language=printer"&gt;Mike Ferguson&lt;/a&gt; &lt;a href="http://www.rawstory.com/news/2006/Congresswoman_on_page_board_buried_file_1019.html"&gt;Heather Wilson&lt;/a&gt; &lt;a href="http://www.newsday.com/news/nationworld/ny-usking0817,0,6911475,print.story?coll=ny-top-headlines"&gt;Peter King&lt;/a&gt; &lt;a href="http://blogs.timesunion.com/capitol/?p=983"&gt;John Sweeney&lt;/a&gt; &lt;a href="http://www.democratandchronicle.com/apps/pbcs.dll/article?AID=/20061004/NEWS01/61004020/1002/NEWS"&gt;Tom Reynolds&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Randy_Kuhl#Personal"&gt;Randy Kuhl&lt;/a&gt; &lt;a href="http://www.newsobserver.com/291/story/254053.html"&gt;Robin Hayes&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Charles_H._Taylor#Controversies"&gt;Charles Taylor&lt;/a&gt; &lt;a href="http://www.thehill.com/thehill/export/TheHill/News/Frontpage/091906/chabot.html"&gt;Steve Chabot&lt;/a&gt; &lt;a href="http://www.wcpo.com/news/2006/local/10/11/murtha_schmidt.html"&gt;Jean Schmidt&lt;/a&gt; &lt;a href="http://www.columbusdispatch.com/?story=217625"&gt;Deborah Pryce&lt;/a&gt; &lt;a href="http://www.cleveland.com/news/plaindealer/index.ssf?/base/news/1161257895268090.xml&amp;amp;coll=2"&gt;Joy Padgett&lt;/a&gt; &lt;a href="http://www.sharonherald.com/local/local_story_263230124.html?start:int=0"&gt;Melissa Hart&lt;/a&gt; &lt;a href="http://www.phillyburbs.com/pb-dyn/news/28-10162006-727801.html"&gt;Curt Weldon&lt;/a&gt; &lt;a href="http://www.phillyburbs.com/pb-dyn/news/111-01222006-601349.html"&gt;Mike Fitzpatrick&lt;/a&gt; &lt;a href="http://www.timesleader.com/mld/timesleader/15646184.htm"&gt;Don Sherwood&lt;/a&gt; &lt;a href="http://www.washingtonpost.com/wp-dyn/content/article/2006/08/05/AR2006080500823.html"&gt;Lincoln Chafee&lt;/a&gt; &lt;a href="http://www.knoxnews.com/kns/election/article/0,1406,KNS_630_5057450,00.html"&gt;Bob Corker&lt;/a&gt; &lt;a href="http://www.cbsnews.com/stories/2006/09/26/politics/main2039589.shtml"&gt;George Allen&lt;/a&gt; &lt;a href="http://www.nationalcenter.org/PRJTHGWolfEarmark1006.html"&gt;Frank Wolf&lt;/a&gt; &lt;a href="http://seattlepi.nwsource.com/local/283622_mcgavick02.html"&gt;Mike McGavick&lt;/a&gt; &lt;a href="http://seattlepi.nwsource.com/local/287797_reichertsideweb06.html"&gt;Dave Reichert&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-116178605370230848?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/116178605370230848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=116178605370230848' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/116178605370230848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/116178605370230848'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2006/10/just-in-case-you-hadnt-read-about.html' title='Just in case you hadn&apos;t read about the Republicans who are running for congress in 2 weeks'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-116054458980258432</id><published>2006-10-10T22:24:00.000-07:00</published><updated>2006-10-10T22:39:01.946-07:00</updated><title type='text'>But...but...we haven't been attacked again since 9/11!</title><content type='html'>May I remind you that we've now lost about as many soldiers in Iraq as we lost civilians.  Iraqis have lost something like 8 to 20 times as many civilians.  Terrorist attacks have skyrocketed since 9/11 worldwide.  We weren't attacked for five years before 9/11 either on U.S. soil, unless you count the Oklahoma City bombing.&lt;br /&gt;&lt;br /&gt;What, you want a smug response to this canard?  OK, how about: that's like saying we didn't get robbed again since we started leaving stacks of $100 bills on the corner every night.&lt;br /&gt;&lt;br /&gt;Any other good metaphors?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-116054458980258432?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/116054458980258432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=116054458980258432' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/116054458980258432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/116054458980258432'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2006/10/butbutwe-havent-been-attacked-again.html' title='But...but...we haven&apos;t been attacked again since 9/11!'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-23435402.post-114152071939152696</id><published>2006-03-04T16:54:00.001-08:00</published><updated>2006-10-10T22:51:10.776-07:00</updated><title type='text'>I like strong polymorphic type disciplines.  I dislike Republicans.</title><content type='html'>The title says it all.  Convince me otherwise.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/23435402-114152071939152696?l=jazzjuice.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jazzjuice.blogspot.com/feeds/114152071939152696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=23435402&amp;postID=114152071939152696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/114152071939152696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/23435402/posts/default/114152071939152696'/><link rel='alternate' type='text/html' href='http://jazzjuice.blogspot.com/2006/03/i-like-strong-polymorphic-type_04.html' title='I like strong polymorphic type disciplines.  I dislike Republicans.'/><author><name>Joshua Caplan</name><uri>https://profiles.google.com/102330163808338316903</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
