<?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'><id>tag:blogger.com,1999:blog-8675640</id><updated>2010-03-09T13:33:38.879-08:00</updated><title type='text'>Public Object</title><subtitle type='html'></subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default'/><link rel='alternate' type='text/html' href='http://publicobject.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://publicobject.com/publicobject/atom.xml'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>254</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8675640.post-1741017701927767875</id><published>2010-03-05T10:57:00.000-08:00</published><updated>2010-03-05T11:44:39.327-08:00</updated><title type='text'>I want !instanceof</title><content type='html'>I'm about a year late for &lt;a href="http://openjdk.java.net/projects/coin/"&gt;project coin&lt;/a&gt;. But I still want an obvious  Java language feature: &lt;code&gt;!instanceof&lt;/code&gt;. To illustrate:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public void equals(Object other) {&lt;br /&gt;    if (other !instanceof Foo) {&lt;br /&gt;      return false;&lt;br /&gt;    }&lt;br /&gt;    return ((Foo) other).bar.equals(bar);&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;With the instanceof operator, &lt;code&gt;null instanceof T&lt;/code&gt; is false for all values of T. Symmetrically, I suppose &lt;code&gt;null !instanceof T&lt;/code&gt; should always be true.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-1741017701927767875?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/1741017701927767875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=1741017701927767875' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1741017701927767875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1741017701927767875'/><link rel='alternate' type='text/html' href='http://publicobject.com/2010/03/i-want-instanceof.html' title='I want !instanceof'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-8185473574344438096</id><published>2010-03-02T21:04:00.000-08:00</published><updated>2010-03-02T21:36:56.793-08:00</updated><title type='text'>MP3 players, crapware and Mac OS X</title><content type='html'>Out of the box, Windows computers work with whichever accessories you buy for them. If you get an MP3 player, it doesn't matter who sells it. Walkman, Zune and Sandisk devices all sync with Windows Media Player.&lt;br /&gt;&lt;br /&gt;But Macs can't do this. Connect a &lt;a href="http://philips.com/GoGear"&gt;GoGear&lt;/a&gt; to a MacBook and you'll have an unsatisfying USB thumbdrive experience. Mac OS X doesn't have a general purpose device sync app!&lt;br /&gt;&lt;br /&gt;Yes, there is iTunes. But it's only there to help Apple sell their wares. It is explicitly programmed to avoid doing general device management. When Palm tried to wire their device into iTunes, Apple &lt;a href="http://www.pcworld.com/printable/article/id,168489/printable.html"&gt;made it explicit&lt;/a&gt; that OS X isn't smart enough to talk to third-party devices:&lt;br /&gt;&lt;blockquote&gt;"Apple does not provide support for, or test for compatibility with, non-Apple digital media players"&lt;br&gt; &amp;nbsp; &amp;nbsp; —Tom Neumayr, Apple spokesperson&lt;/blockquote&gt;&lt;br /&gt;Windows PCs sometimes include &lt;a href="http://arstechnica.com/old/content/2007/01/8598.ars"&gt;crapware&lt;/a&gt; like AOL or the Google Toolbar. This is preinstalled software intended to sell you something; savvy users promptly remove it. iTunes is the same thing. Don't confuse it with an operating system facility; that only leads to heartache.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-8185473574344438096?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/8185473574344438096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=8185473574344438096' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/8185473574344438096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/8185473574344438096'/><link rel='alternate' type='text/html' href='http://publicobject.com/2010/03/mp3-players-crapware-and-mac-os-x.html' title='MP3 players, crapware and Mac OS X'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-3548756157141839277</id><published>2010-02-20T01:02:00.000-08:00</published><updated>2010-02-20T01:18:33.035-08:00</updated><title type='text'>org.w3c.dom WTFs of the week</title><content type='html'>I've been working on bringing Android's DOM implementation up to version 3. This process has exposed me to some ugly code.  For your entertainment, here are the worst bits:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/parsers/DocumentBuilder.html#parse(org.xml.sax.InputSource)"&gt;DocumentBuilder.parse()&lt;/a&gt; doesn't accept references to unparsed entities. But you can build such a DOM programatically.&lt;br /&gt;&lt;li&gt;The API &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/EntityReference.html"&gt;doesn't specify&lt;/a&gt; whether entity references will be expanded at parse time. To be sure, both the parser and its client need to have code that implements entity expansion.&lt;br /&gt;&lt;li&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/Node.html#setTextContent(java.lang.String)"&gt;Node.setTextContent("foo")&lt;/a&gt; silently does nothing for certain node types.&lt;br /&gt;&lt;li&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/Node.html#lookupNamespaceURI(java.lang.String)"&gt;Node.lookupNamespaceURI(null)&lt;/a&gt; disagrees with &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/Node.html#isDefaultNamespace(java.lang.String)"&gt;isDefaultNamespace(String)&lt;/a&gt; for certain node types.&lt;br /&gt;&lt;li&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/Node.html#getFeature(java.lang.String, java.lang.String)"&gt;Node.getFeature()&lt;/a&gt; forces users to map Strings to Java types. Type safety by fortune!&lt;br /&gt;&lt;li&gt;The API bends over backwards to allow competing implementations to interoperate. For example, &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/Node.html#compareDocumentPosition(org.w3c.dom.Node)"&gt;Node.compareDocumentPosition()&lt;/a&gt; throws when&lt;i&gt; "the compared nodes are from different DOM implementations that do not coordinate to return consistent implementation-specific results."&lt;/i&gt; Who does this?&lt;br /&gt;&lt;li&gt;The Javadoc from &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/UserDataHandler.html#NODE_DELETED"&gt;UserDataHandler.NODE_DELETED&lt;/a&gt;: &lt;i&gt;"This may not be supported or may not be reliable in certain environments, such as Java, where the implementation has no real control over when objects are actually deleted."&lt;/i&gt; It says this in &lt;strong&gt;Javadoc!&lt;/strong&gt;&lt;/ul&gt;&lt;br /&gt;I parse XML so you don't have to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-3548756157141839277?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/3548756157141839277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=3548756157141839277' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/3548756157141839277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/3548756157141839277'/><link rel='alternate' type='text/html' href='http://publicobject.com/2010/02/orgw3cdom-wtfs-of-week.html' title='org.w3c.dom WTFs of the week'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-4505883940171872671</id><published>2009-12-15T15:55:00.000-08:00</published><updated>2009-12-15T16:34:52.960-08:00</updated><title type='text'>Hexed by converting ints to hex</title><content type='html'>Java's Integer class includes two methods for converting values into Strings. There's a general one:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;    /**&lt;br /&gt;     * Converts the specified integer into a string representation based on the&lt;br /&gt;     * specified radix.&lt;br /&gt;     */&lt;br /&gt;    public static String toString(int i, int radix) { ... }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Plus there's also methods for commonly used bases:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;    /**&lt;br /&gt;     * Converts the specified integer into its hexadecimal string&lt;br /&gt;     * representation.&lt;br /&gt;     */&lt;br /&gt;    public static String toHexString(int i) { ... }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Converts the specified integer into its octal string representation.&lt;br /&gt;     */&lt;br /&gt;    public static String toOctalString(int i) { ... }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Converts the specified integer into its binary string representation.&lt;br /&gt;     */&lt;br /&gt;    public static String toBinaryString(int i) { ... }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;My expectation was that the first was simply a more general form. Given this assumption, I expected the following program to print the same three lines twice:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public static void main(String... args) {&lt;br /&gt;    System.out.println(Integer.toHexString(0xCAFE));&lt;br /&gt;    System.out.println(Integer.toHexString(0xBABE));&lt;br /&gt;    System.out.println(Integer.toHexString(0xCAFEBABE));&lt;br /&gt;    System.out.println(Integer.toString(0xCAFE, 16));&lt;br /&gt;    System.out.println(Integer.toString(0xBABE, 16));&lt;br /&gt;    System.out.println(Integer.toString(0xCAFEBABE, 16));&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;But it turns out that negative numbers have slightly surprising results when combined with arbitrary bases. The program prints the following:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;cafe&lt;br /&gt;babe&lt;br /&gt;cafebabe&lt;br /&gt;cafe&lt;br /&gt;babe&lt;br /&gt;-35014542&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;If you're emitting hex or binary data, you probably should avoid &lt;nobr&gt;&lt;a href="http://developer.android.com/reference/java/lang/Integer.html#toString(int,%20int)"&gt;toString(int value, int radix)&lt;/a&gt;&lt;/nobr&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-4505883940171872671?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/4505883940171872671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=4505883940171872671' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4505883940171872671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4505883940171872671'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/12/hexed-by-converting-ints-to-hex.html' title='Hexed by converting ints to hex'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-919776253343195936</id><published>2009-11-19T22:24:00.000-08:00</published><updated>2009-11-19T23:41:16.182-08:00</updated><title type='text'>Floating point equality</title><content type='html'>In working through &lt;a href="http://svn.apache.org/viewvc?view=revision&amp;amp;revision=882364"&gt;some bugs&lt;/a&gt; in Harmony, one thing that's been consistent is my surprise. Floating point's special values slightly complicate things...&lt;br /&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;strong&gt;Negative Zero&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;Floats and doubles have two distinct representations for nada: &lt;code&gt;0.0F&lt;/code&gt; and &lt;code&gt;&lt;nobr&gt;-0.0F&lt;/nobr&gt;&lt;/code&gt;.&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;&lt;strong&gt;NaN&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;Rather than risking an ArithmeticException, floats model error values natively. There are multiple binary representations of NaN; use &lt;a href="http://developer.android.com/reference/java/lang/Float.html#floatToRawIntBits(float)"&gt;floatTo&lt;strong&gt;Raw&lt;/strong&gt;IntBits()&lt;/a&gt; to see yours. Most developers will prefer &lt;a href="http://developer.android.com/reference/java/lang/Float.html#floatToIntBits(float)"&gt;floatToIntBits()&lt;/a&gt;, which returns the same bits for all NaNs.&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;&lt;br /&gt;There's also a variety of ways to store floating point values. Each representation has its own merits and drawbacks:&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;strong&gt;Primitives&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;Fast, memory efficient, and nonnull.&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;&lt;strong&gt;In wrappers&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;Classes like Float and Double can be used in collections. Wrapper variables are nullable and implement convenient APIs from Number and Comparable.&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;&lt;strong&gt;In buffers&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;FloatBuffer and DoubleBuffer store nonnull values in bulk. Buffers provide direct access to data in files and streams.&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, the interplay between the values and their representation is imperfect. Consider how equality differs by value and representation.&lt;br /&gt;&lt;blockquote&gt;&lt;table border="1" width="100%" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Values&lt;/th&gt;&lt;th&gt;Primitives&lt;br&gt;&lt;code&gt;==&lt;/code&gt;&lt;/th&gt;&lt;th&gt;In wrappers&lt;br&gt;&lt;code&gt;Object.equals()&lt;/code&gt;&lt;/th&gt;&lt;th&gt;In buffers&lt;br&gt;&lt;code&gt;Buffer.equals()&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;-0.0, +0.0&lt;/th&gt;&lt;td align="center"&gt;equal&lt;/td&gt;&lt;td align="center"&gt;not equal&lt;/td&gt;&lt;td align="center"&gt;equal&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;NaN, NaN&lt;/th&gt;&lt;td align="center"&gt;not equal&lt;/td&gt;&lt;td align="center"&gt;equal&lt;/td&gt;&lt;td align="center"&gt;equal&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/blockquote&gt;&lt;br /&gt;This behaviour is inconsistent but I suspect the differences weren't introduced lightly. Primitive types need to work in expressions so that &lt;code&gt;5/0&lt;/code&gt; doesn't equal &lt;code&gt;0/0&lt;/code&gt;. But wrapper types need to work in collections so that &lt;code&gt;Set.add()&lt;/code&gt; is consistent with &lt;code&gt;Set.contains()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;On their own, exotic values and exotic representations both make sense. But since complexity is the N×M product of the feature set, our result is inevitable pain. Would be language designers should prefer fewer representations and fewer special values.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-919776253343195936?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/919776253343195936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=919776253343195936' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/919776253343195936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/919776253343195936'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/11/floating-point-equality.html' title='Floating point equality'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-7954172921073008902</id><published>2009-11-09T20:56:00.000-08:00</published><updated>2009-11-09T21:36:54.797-08:00</updated><title type='text'>iPhone Storage</title><content type='html'>John Gruber &lt;a href="http://daringfireball.net/linked/2009/11/09/droid-app-storage"&gt;praises&lt;/a&gt; the iPhone's lack of upgradeable storage:&lt;br /&gt;&lt;blockquote&gt; I simply don’t understand why Motorola doesn’t follow Apple’s lead and provide ample built-in storage rather than relying on removable SD cards.&lt;/blockquote&gt;&lt;br /&gt;He overlooks an obvious benefit of having SD cards for storage: they're cheaper! Compare what it costs to equip a device with a substantial amount of memory:&lt;br /&gt;&lt;blockquote&gt;&lt;table align="center" cellspacing="0" border="1" width="100%"&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;iPhone 3G S&lt;/th&gt;&lt;th&gt;Droid&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;16GB&lt;/th&gt;&lt;td align="center"&gt;$199&lt;/td&gt;&lt;td align="center"&gt;$199&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;32GB&lt;/th&gt;&lt;td align="center"&gt;$299&lt;/td&gt;&lt;td align="center"&gt;$279&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;/table&gt;&lt;/blockquote&gt;&lt;br /&gt;Apple has a long history of gouging its customers on non-upgradeable memory. 32GB of data is the maximum amount that iPhone users may accumulate. Droid users who have &amp;gt;32GB of data can shuffle multiple cards.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-7954172921073008902?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/7954172921073008902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=7954172921073008902' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/7954172921073008902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/7954172921073008902'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/11/iphone-storage.html' title='iPhone Storage'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-4897976871580728459</id><published>2009-10-28T00:46:00.001-07:00</published><updated>2009-10-28T01:04:05.370-07:00</updated><title type='text'>Champagne Floats</title><content type='html'>Suppose you've got a string that contains a floating point number: "3.5" or "2.5E-3". Your goal is to get a &lt;code&gt;float&lt;/code&gt; from that number. There are a few different techniques to try...&lt;br /&gt;&lt;br /&gt;If you're familiar with &lt;a href="http://developer.android.com/reference/java/lang/Double.html#parseDouble(java.lang.String)"&gt;parseDouble()&lt;/a&gt;, you could use that and then cast:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;    String s = ...;&lt;br /&gt;    float a = (float) Double.parseDouble(s);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Or you could save some bits and parse directly using &lt;a href="http://developer.android.com/reference/java/lang/Float.html#parseFloat(java.lang.String)"&gt;parseFloat()&lt;/a&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;    String s = ...;&lt;br /&gt;    float b = Float.parseFloat(s);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Do the two mechanisms yield the same result?&lt;/h3&gt;&lt;br /&gt;Ponder the problem, and when you're ready you can read my analysis in the comments...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-4897976871580728459?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/4897976871580728459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=4897976871580728459' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4897976871580728459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4897976871580728459'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/10/champagne-floats.html' title='Champagne Floats'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-3504286510865494766</id><published>2009-10-16T23:36:00.001-07:00</published><updated>2009-10-17T00:19:41.331-07:00</updated><title type='text'>IntelliJ goes open source!</title><content type='html'>I absolutely love &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt;; it's my favourite application. This tool makes programming in Java fun. It's my gateway to the zone, that magical hypnotic place where I disappear into the code for hours at a time. I write better code because I use IntelliJ, and I enjoy my job more.&lt;br /&gt;&lt;br /&gt;So I am thrilled that the fine folks at JetBrains are open sourcing the core of their flagship product. The &lt;a href="http://www.jetbrains.com/idea/nextversion/free_java_ide.html"&gt;Community Edition&lt;/a&gt; includes the key features that make using it fun. Hooray!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://beust.com/weblog/archives/000520.html"&gt;Cedric doubts&lt;/a&gt; that going open source is a good idea:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;"JetBrains deserves the utmost respect for what they have created and pioneered, but IDEA going opensource means that it will now slowly die. [...] Commercial software that goes open source never ends well, even for products that don't suck.&lt;/i&gt;&lt;/blockquote&gt;I disagree. I predict that going open source will increase the product's revenue. Consider the universe of all Java programmers. JetBrains' potential customer base is limited to those developers that are &lt;strong&gt;both&lt;/strong&gt;:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Fans of IntelliJ&lt;/strong&gt;. Knowing an IDE deeply is similar to knowing a programming language deeply.&lt;li&gt;&lt;strong&gt;People willing to pay for good tools&lt;/strong&gt;. These are the serious developers who recognize that their productivity and enjoyment is heavily impacted by their choice of IDE.&lt;/li&gt;&lt;/ol&gt;This is a small intersection, particularly since many developers start with an open source IDE and never try anything else:&lt;br /&gt;&lt;blockquote&gt;&lt;center&gt;&lt;img src="/uploaded_images/Picture-61-797249.png"&gt;&lt;/center&gt;&lt;/blockquote&gt;&lt;br /&gt;Now let's assume that by going open source, more developers will try IntelliJ to see what the fuss is about. They'll fall in love with it eventually. Those willing to pay will upgrade for some productivity-boosting premium features.&lt;br /&gt;&lt;blockquote&gt;&lt;center&gt;&lt;img src="/uploaded_images/Picture-62-741817.png"&gt;&lt;/center&gt;&lt;/blockquote&gt;&lt;br /&gt;As the IntelliJ userbase grows, the premium edition ownership will follow. &lt;br /&gt;&lt;br /&gt;This free/premium model is also used by Flickr and Flickr Pro: give away community editions (which cost nothing) to sell premium editions. Chris Anderson's latest book, &lt;a href="http://www.amazon.com/gp/product/1401322905"&gt;Free&lt;/a&gt; covers this subject in detail. It's an entertaining read, and you can get a &lt;a href="http://books.google.com/books?id=lLZbXN2odVYC&amp;lpg=PP1&amp;pg=PP1#v=onepage&amp;q=&amp;f=false"&gt;community edition of the book&lt;/a&gt; for no charge.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-3504286510865494766?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/3504286510865494766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=3504286510865494766' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/3504286510865494766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/3504286510865494766'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/10/intellij-goes-open-source.html' title='IntelliJ goes open source!'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-8054206265989054885</id><published>2009-08-17T21:27:00.001-07:00</published><updated>2009-08-17T21:47:03.174-07:00</updated><title type='text'>Shush! Ringer Restorer</title><content type='html'>I just uploaded a new Android app, &lt;a href="http://publicobject.com/shush/"&gt;Shush! Ringer Restorer&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;img src="/shush/icon.png" align="right"&gt;When you turn your ringer off for a movie, this app turns it back on afterwards.&lt;br /&gt;&lt;p&gt;It's activated when you silence your ringer using the volume buttons. You don't need to remember a special app! Once your ringer is off, it asks you how long to stay silent: ½, 1, 2 or 3 hours. Never miss another important call!&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;I'm familiar with the Android tools, but this is the first app I've written. The whole project took around 16 hours, including &lt;a href="http://developer.android.com/sdk/1.5_r3/index.html"&gt;downloading the SDK&lt;/a&gt;, &lt;a href="http://developer.android.com/reference/android/media/AudioManager.html"&gt;writing the code&lt;/a&gt;, &lt;a href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html"&gt;drawing icons&lt;/a&gt;, &lt;a href="http://developer.android.com/guide/developing/tools/emulator.html"&gt;testing&lt;/a&gt;, &lt;a href="http://www.android.com/market/"&gt;publishing&lt;/a&gt;, and &lt;a href="http://code.google.com/p/publicobject/source/browse/shush/"&gt;open sourcing&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;I love Android because it enables apps like this one. My app receives ringer changes, opens dialogs with a polished UI, schedules background tasks, and turns on the ringer. I wrote in on Sunday and my friends downloaded it on Monday. I couldn't do any of this on the other device platforms.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Shush!&lt;/i&gt; was a fun project, and I'm now brainstorming a more ambitious follow-up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-8054206265989054885?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/8054206265989054885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=8054206265989054885' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/8054206265989054885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/8054206265989054885'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/08/shush-ringer-restorer.html' title='Shush! Ringer Restorer'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-7957549450822047215</id><published>2009-06-03T07:49:00.000-07:00</published><updated>2009-06-03T09:03:39.547-07:00</updated><title type='text'>I dig the Creative Commons</title><content type='html'>Joe Clark, author of a fantastic book on &lt;a href="http://en-ca.org/"&gt;Canadian English&lt;/a&gt; and a childish &lt;a href="http://blog.fawny.org/2009/04/26/google-neuroanatomy/"&gt;rant about Google employees&lt;/a&gt; is at it again. This time he's planning a book about how copyright benefits creative people:&lt;br /&gt;&lt;blockquote&gt;Who’s sticking up for the individual creator? Neither side is. The maximalist side wants to collect as many copyrights under a corporate umbrella as possible, guarding them forever. The minimalist side wants you to voluntarily surrender most of your important rights – also forever – on the off chance that “the culture” might someday wish to use your work.&lt;/blockquote&gt;&lt;br /&gt;I read Mark Helprin's &lt;a href="http://www.amazon.com/Digital-Barbarism-Manifesto-Mark-Helprin/dp/0061733113"&gt; Digital-Barbarism&lt;/a&gt; on the same topic. That book was entertaining, but it's more of an old man's rant than a reasoned argument. I assume Mr. Clark will be more disciplined, and &lt;i&gt;read&lt;/i&gt; about copyright before he starts to &lt;i&gt;write&lt;/i&gt; about copyright.&lt;br /&gt;&lt;br /&gt;One premise of the new book is that creative commons is a &lt;a href="http://joeclark.org/cranky/issues/anticommons/"&gt;bad idea&lt;/a&gt;. You sign up for creative commons because of peer pressure and don’t even know what you’re signing away. Naturally I feel compelled to share some counter examples that demonstrate the benefit of creative commons, from both sides of the copyright transaction. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;As a creative person&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/swankjesse/47581690/"&gt;&lt;img src="http://publicobject.com/uploaded_images/Picture-34-743063.png" align="right" /&gt;&lt;/a&gt;While in highschool, I created a &lt;a href="http://swank.ca/caffeen/fonts/"&gt;few dozen fonts&lt;/a&gt; and gave them away under a liberal license (creative commons didn't exist in 1997). I created the fonts because I enjoyed doing so, not because I wanted to become the next &lt;a href="http://www.chank.com/"&gt;Britney Spears of fonts&lt;/a&gt;. By lowering the cost of using my fonts (to zero!), their use increased. There are &lt;a href="http://www.fontsnthings.com/"&gt;great&lt;/a&gt; &lt;a href="http://www.1001fonts.com/"&gt;websites&lt;/a&gt; organized around sharing free fonts. As a consequence, I get to see my creative works in the wild. I've seen 'em in everything from &lt;a href="http://www.flickr.com/photos/swankjesse/261230779/"&gt;video&lt;/a&gt; &lt;a href="http://www.amazon.com/Big-League-Sports-Nintendo-Wii/dp/B001CDL6WA"&gt;games&lt;/a&gt; &lt;a href="http://www.flickr.com/photos/swankjesse/47581690/"&gt;to&lt;/a&gt; &lt;a href="http://www.flickr.com/photos/swankjesse/27727291/"&gt;tattoos&lt;/a&gt;. One reason people prefer my fonts over the esthetically superior commercial ones is that they don't need permission to use mine! &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;As a consumer of creative works&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/swankjesse/3493386838/"&gt;&lt;img src="http://publicobject.com/uploaded_images/3493386838_04de7c475a_m-708189.jpg" align="left"/&gt;&lt;/a&gt;Recently I've been giving tech talks at conferences. I get bored by text-only slides, so I've made my own presentation more interesting with pictures. For example, when explaining the &lt;code&gt;Provider&lt;/code&gt; abstraction, I like to show a &lt;a href="http://www.flickr.com/photos/toasty/535851893/"&gt;Pez Dispenser&lt;/a&gt;. The pictures are nice-to-have, but not essential. If I needed permission, I probably wouldn't include the pictures! It's a simple consequence of logistics — I may assemble the slides 48 hours before they're shown, but it takes longer than that to negotiate permission. Thanks to creative commons, I have a prettier slide deck.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The long tail&lt;/h3&gt;&lt;br /&gt;One of Joe Clark's budding arguments is that only the A-list content get remixed. As an amateur artist and a consumer of amateur art, I disagree. Unless you're doing it for the money, consider licensing your photos, fonts, music, drawings and writing under a creative-commons license. It allows other to showcase your talent!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-7957549450822047215?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/7957549450822047215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=7957549450822047215' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/7957549450822047215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/7957549450822047215'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/06/i-dig-creative-commons.html' title='I dig the Creative Commons'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-1799213143961417650</id><published>2009-05-21T19:57:00.000-07:00</published><updated>2009-05-21T21:45:38.295-07:00</updated><title type='text'>Inside Guice 2: exercising elements</title><content type='html'>&lt;i&gt;Part 3 in a &lt;a href="http://publicobject.com/2009/05/inside-guice-2-binder-sources.html"&gt;Series&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Background: modelling configuration&lt;/h3&gt;&lt;br /&gt;One of the most distinct features of Guice is our fluent embedded domain specific language (DSL). By chaining method calls, Guice supports a wide combination of binding sources, targets and scopes:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;    bind(PaymentService.class)&lt;br /&gt;        .annotatedWith(Names.named("creditCard"))&lt;br /&gt;        .to(VisaPaymentService.class)&lt;br /&gt;        .in(RequestScoped.class);&lt;br /&gt;&lt;br /&gt;    bind(new TypeLiteral&amp;lt;Connector&amp;lt;Processor&amp;gt;&amp;gt;() {})&lt;br /&gt;        .annotatedWith(Online.class);&lt;br /&gt;        .toProvider(new CheckoutProcessorConnectorProvider());&lt;br /&gt;&lt;br /&gt;    bind(TransactionLog.class)&lt;br /&gt;        .toInstance(new InMemoryTransactionLog());&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In our first implementation of the DSL, calls to bind() etc. configured the injector directly. This works well, but it's not very flexible. As long as creating injectors is &lt;i&gt;all&lt;/i&gt; that we do with modules, it's sufficient.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Elements SPI&lt;/h3&gt;&lt;br /&gt;In Guice 2, the DSL is used to build an intermediate configuration model. Calls to bind() etc. create &lt;code&gt;Element&lt;/code&gt; instances. For example, the three statements above will create a &lt;code&gt;LinkedKeyBinding&lt;/code&gt;, a &lt;code&gt;ProviderInstanceBinding&lt;/code&gt; and an &lt;code&gt;InstanceBinding&lt;/code&gt;. The API to get the configuration model from a module is called &lt;a href="http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spi/Elements.html"&gt;Elements.getElements()&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;By converting the method calls into value objects, we get an opportunity to inspect and transform them. For example, the following prints all of the keys bound in a module:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public static Set&amp;lt;Key&amp;lt;?&amp;gt;&amp;gt; getBoundKeys(Module module) {&lt;br /&gt;    Set&amp;lt;Key&amp;lt;?&amp;gt;&amp;gt; result = newHashSet();&lt;br /&gt;    for (Element element : Elements.getElements(module)) {&lt;br /&gt;      if (element instanceof Binding) {&lt;br /&gt;        result.add(((Binding) element).getKey());&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return result;&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Internally, we use this API to simplify injector creation. Now we can process elements in order we want, even when that's different from the order that the user has specified. We prefer to handle scope registrations before bindings, and bindings before injection requests.&lt;br /&gt;&lt;br /&gt;These elements are useful in other APIs. For module overrides, we take elements from two modules and compute a union. We can also use elements to unit test modules without having their dependencies on hand. They'll also come in handy for development tools.&lt;br /&gt;&lt;br /&gt;By converting method calls into value objects, we can do powerful new things.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-1799213143961417650?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/1799213143961417650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=1799213143961417650' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1799213143961417650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1799213143961417650'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/05/inside-guice-2-exercising-elements.html' title='Inside Guice 2: exercising elements'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-4878146437437603086</id><published>2009-05-19T21:19:00.000-07:00</published><updated>2009-05-22T10:42:13.541-07:00</updated><title type='text'>Inside Guice 2: injecting null</title><content type='html'>&lt;i&gt;Part 2 in a &lt;a href="/2009/05/inside-guice-2-binder-sources.html"&gt;Series&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Background: marking nulls&lt;/h3&gt;&lt;br /&gt;Null is bad. Most of the time, use of &lt;code&gt;null&lt;/code&gt; indicates clumsy modeling. Instead of null collections, use empty ones. Instead of a null service, use a no-op implementation. The JDK gets this wrong for comparators by using &lt;code&gt;null&lt;/code&gt; as a stand-in for &lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Ordering.html#natural()"&gt;natural order&lt;/a&gt;; the result is special cases instead of polymorphism.&lt;br /&gt;&lt;br /&gt;To help you to detect null problems sooner, Guice &lt;strong&gt;refuses&lt;/strong&gt; to inject null by default. When asked to do so, it will fail with a &lt;code&gt;ProvisionException&lt;/code&gt; instead. This increases your confidence in your app by eliminating an entire category of runtime problems.&lt;br /&gt;&lt;br /&gt;But sometimes — and only sometimes — null is necessary. Value objects don't lend themselves to the null object pattern. And in some cases you can be sure that a null reference won't be used. To make intentional null use explicit, you can use one of several &lt;code&gt;@Nullable&lt;/code&gt; annotations, including those from &lt;a href="http://findbugs.sourceforge.net/api/edu/umd/cs/findbugs/annotations/Nullable.html"&gt;FindBugs&lt;/a&gt;, &lt;a href="http://www.jetbrains.com/idea/documentation/howto.html"&gt;IntelliJ&lt;/a&gt; or old snapshots of &lt;a href="http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/Nullable.java?r=71"&gt;Google Collections&lt;/a&gt;. These will soon be standardized by another &lt;code&gt;@Nullable&lt;/code&gt; in &lt;a href="http://code.google.com/p/jsr-305/source/browse/trunk/ri/src/main/java/javax/annotation/Nullable.java?r=24"&gt;JSR 305&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Injecting null&lt;/h3&gt;&lt;br /&gt;Guice tolerates &lt;code&gt;null&lt;/code&gt; to be injected wherever a parameter is annotated &lt;code&gt;@Nullable&lt;/code&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public Person(String firstName, String lastName, @Nullable Phone phone) {&lt;br /&gt;    this.firstName = checkNotNull(firstName, "firstName");&lt;br /&gt;    this.lastName = checkNotNull(lastName, "lastName");&lt;br /&gt;    this.phone = phone;&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;But which &lt;code&gt;@Nullable&lt;/code&gt;?&lt;br /&gt;&lt;br /&gt;Rather than arbitrarily choosing an &lt;code&gt;@Nullable&lt;/code&gt; to support (and alienating everyone else), Guice permits any &lt;code&gt;Nullable&lt;/code&gt; annotation to be used. And I do mean &lt;i&gt;any&lt;/i&gt;: it scans the injected parameter or field's annotations, looking at their names. If any has the simple name &lt;code&gt;Nullable&lt;/code&gt;, it is honoured. This means that  even your company's internal &lt;code&gt;com.company.util.Nullable&lt;/code&gt; will work.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;More generally&lt;/h3&gt;&lt;br /&gt;This trick works particularly nicely for annotations, since they tag objects without adding behaviour. It also avoids an aggravating problem, where code that &lt;i&gt;looks&lt;/i&gt; right doesn't &lt;i&gt;work&lt;/i&gt; right. Consider:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;import com.google.inject.Inject;&lt;br /&gt;import javax.annotation.Named;&lt;br /&gt;&lt;br /&gt;public class RealPaymentService implements PaymentService {&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  public RealPaymentService(@Named("creditcard") Processor processor) {&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This code appears legitimate, and it might even execute without error. But the wrong &lt;code&gt;@Named&lt;/code&gt; annotation is applied! The unreleased &lt;code&gt;javax.annotation.Named&lt;/code&gt; is incompatible with Guice and has no effect. Since it &lt;i&gt;looks&lt;/i&gt; the same as &lt;code&gt;com.google.inject.name.Named&lt;/code&gt;, there's potential for error.&lt;br /&gt;&lt;br /&gt;When applying annotations, be careful about overlapping names. When processing them, be mindful of mistakes! What's the annotation-equivalent of a precondition? If a user applies an annotation incorrectly, is it detected?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://publicobject.com/2009/05/inside-guice-2-exercising-elements.html"&gt;Part 3&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-4878146437437603086?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/4878146437437603086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=4878146437437603086' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4878146437437603086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4878146437437603086'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/05/inside-guice-2-injecting-null.html' title='Inside Guice 2: injecting null'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-13546945163994002</id><published>2009-05-19T19:45:00.000-07:00</published><updated>2009-05-19T22:25:42.792-07:00</updated><title type='text'>Inside Guice 2: binder sources</title><content type='html'>To celebrate the &lt;a href="http://google-code-updates.blogspot.com/2009/05/guice-deuce.html"&gt;release of Guice 2.0&lt;/a&gt;, I'd like to showcase my favourite parts of the new code. In this &lt;i&gt;N&lt;/i&gt;-part series, I'll go deep into the implementation details to explain the clever and interesting code within the project. I'll focus on general techniques that you can use in your own applications.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Background: Getting sources&lt;/h3&gt;&lt;br /&gt;When you invoke methods on a &lt;code&gt;Binder&lt;/code&gt; (or invoke them indirectly, via &lt;code&gt;AbstractModule&lt;/code&gt;), Guice captures the caller's source. This is used to create javac-like error messages in the event of a configuration problem. For example, the following binding is illegal because &lt;code&gt;Executor&lt;/code&gt; is an interface without an implementation:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;class BadModule extends AbstractModule {&lt;br /&gt;  protected void configure() {&lt;br /&gt;    bind(Executor.class);&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;When this faulty module is used to create an injector, Guice reports the problem with the source line where it occurred:&lt;br /&gt;&lt;pre&gt;Exception in thread "main" com.google.inject.CreationException: Guice creation errors:&lt;br /&gt;&lt;br /&gt;1) No implementation for java.util.concurrent.Executor was bound.&lt;br /&gt;  at com.publicobject.blog.Scratch$1.configure(Scratch.java:18)&lt;br /&gt;&lt;br /&gt;1 error&lt;/pre&gt;&lt;br /&gt;To obtain the offending source line, Guice grabs a stacktrace using &lt;code&gt;new Throwable().getStackTrace()&lt;/code&gt; and scans through its frames to find the logical source. It has to ignore some classes: &lt;code&gt;AbstractModule.java&lt;/code&gt;, &lt;code&gt;RecordingBinder.java&lt;/code&gt;, etc.&lt;br /&gt;&lt;br /&gt;The stacktrace grabbing trick is &lt;i&gt;extremely&lt;/i&gt; cool, but it's not sufficient. Guice can't always know the full set of classes that it should skip. Extensions like &lt;a href="http://code.google.com/p/google-guice/wiki/Multibindings"&gt;Multibinder&lt;/a&gt; create bindings on their user's behalf and need to omit additional classes from the trace (&lt;code&gt;RealMultibinder.java&lt;/code&gt;, &lt;code&gt;Multibinder.java&lt;/code&gt;). And &lt;a href="http://code.google.com/p/google-guice/wiki/ProvidesMethods"&gt;Provider Methods&lt;/a&gt; specify their source as a method name instead of relying on a stack trace.&lt;br /&gt;&lt;br /&gt;We need an API to specify which classes to skip in stacktraces, and another API to specify a source object directly.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Binder Sources&lt;/h3&gt;&lt;br /&gt;The difficulty in finding a nice API for configuring sources is that it's naturally temporal. We want to specify a source, use it for a binding or two, and then reset it back:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public void configure(Binder binder) {&lt;br /&gt;    Method method = ...&lt;br /&gt;    &lt;strong&gt;Object previous = binder.getSource();&lt;br /&gt;    binder.setSource(method);&lt;/strong&gt;&lt;br /&gt;    try {&lt;br /&gt;      binder.bind(method.getGenericReturnType())&lt;br /&gt;          .toProvider(new ProviderMethod(method));&lt;br /&gt;    } finally {&lt;br /&gt;      &lt;strong&gt;binder.setSource(previous);&lt;/strong&gt;&lt;br /&gt;    }&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Yuck.&lt;br /&gt;&lt;br /&gt;Taking inspiration from &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/List.html#subList(int,%20int)"&gt;List.subList()&lt;/a&gt;, our approach is to instead return a &lt;i&gt;new&lt;/i&gt; binder that works with the provided source:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public void configure(Binder binder) {&lt;br /&gt;    Method method = ...&lt;br /&gt;    &lt;strong&gt;Binder sourcedBinder = binder.withSource(method);&lt;/strong&gt;&lt;br /&gt;    &lt;strong&gt;sourcedBinder&lt;/strong&gt;.bind(method.getGenericReturnType())&lt;br /&gt;          .toProvider(new ProviderMethod(method));&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Every binding, injection or configuration applied to &lt;code&gt;sourcedBinder&lt;/code&gt; will use the user-specified source. But the passed-in binder is untouched. With some inlining and the binder's existing embedded DSL, the whole thing can be a single statement:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public void configure(Binder binder) {&lt;br /&gt;    Method method = ...&lt;br /&gt;    &lt;strong&gt;binder.withSource(method)&lt;/strong&gt;&lt;br /&gt;          .bind(method.getGenericReturnType())&lt;br /&gt;          .toProvider(new ProviderMethod(method));&lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This new API is cute and fits nicely with the existing code.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://publicobject.com/2009/05/inside-guice-2-injecting-null.html"&gt;Part 2&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-13546945163994002?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/13546945163994002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=13546945163994002' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/13546945163994002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/13546945163994002'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/05/inside-guice-2-binder-sources.html' title='Inside Guice 2: binder sources'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-1955876021526227053</id><published>2009-05-07T23:52:00.000-07:00</published><updated>2009-05-08T02:57:11.930-07:00</updated><title type='text'>My perspective on Atinject</title><content type='html'>Back in February, a discussion &lt;a href="http://code.google.com/p/google-guice/issues/detail?id=258"&gt;flared up&lt;/a&gt; over Guice's lack of support for industry-standard annotations. James Strachan described the problem succinctly: &lt;br /&gt;&lt;blockquote&gt;So my show stopper issue with ever adopting &amp; recommending Guice is to be able to use IoC framework agnostic annotations for lifecycle &amp; injection (JSR 250/EJB3 for starters, @Resource, @PostConstruct, @PreDestroy - you could throw Spring/WebBeans/JAX-RS/JAXWs in there too really but JSR250/EJB3 is the tip of this massive iceberg). i.e. so that my application code can be used by Spring or Guice IoC containers without having to double-annotate everything (using JSR 250 and Guice annotations) or using JSR 250 annotations then forcing producer methods for every class I write to be written by users using Guice. &lt;/blockquote&gt;&lt;br /&gt;In response to the immediate issue, Guice got support for &lt;a href="http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/MembersInjector.html"&gt;custom injectors&lt;/a&gt;. And we're planning an API for lifecycle callbacks.&lt;br&gt;&lt;br&gt;&lt;hr width="25%" align="center"&gt;&lt;br&gt;&lt;br&gt;Unfortunately, the current annotations aren't really sufficient. &lt;a href="http://java.sun.com/javase/6/docs/api/javax/annotation/Resource.html"&gt;@Resource&lt;/a&gt; precludes immutability. It lacks a compiler-checked way to qualify a type. And it lacks a mechanism for lazy or multiple injection.&lt;br /&gt;&lt;br /&gt;Since @Resource is mostly a non-starter, each of the established containers defines its own annotations:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;public class TweetsClient {&lt;br /&gt;&lt;br /&gt;  @Autowired&lt;br /&gt;  @com.google.inject.Inject&lt;br /&gt;  @org.apache.tapestry5.ioc.annotations.Inject&lt;br /&gt;  public TweetsClient(OpenIdCredentials credentials,&lt;br /&gt;      HttpConnectionFactory connectionFactory) {&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The differences between these are superficial. There just aren't many ways to mark an injection point!&lt;br /&gt;&lt;br /&gt;To unity their annotations, the established Java dependency injection vendors collaborated on a &lt;a href="http://code.google.com/p/atinject/"&gt;new API&lt;/a&gt; to serve as a common standard. The entire API is five annotations (including &lt;a href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Inject.html"&gt;@Inject&lt;/a&gt;) plus &lt;a href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Provider.html"&gt;Provider&lt;/a&gt; for lazy/multiple injection.&lt;br /&gt;&lt;br /&gt;The spec enables &lt;strong&gt;class portability&lt;/strong&gt;. Your classes can be used with any injector: annotate implementation class once to support all of &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt;, &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice&lt;/a&gt;, &lt;a href="http://www.picocontainer.org/"&gt;PicoContainer&lt;/a&gt;, &lt;a href="http://tapestry.apache.org/tapestry5/tapestry-ioc/"&gt;Tapestry IoC&lt;/a&gt;, and &lt;a href="http://code.google.com/p/simject/"&gt;Simject&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;hr width="25%" align="center"&gt;&lt;br&gt;&lt;br&gt;But the new standard &lt;i&gt;does not&lt;/i&gt; cover injector configuration. The lack of standardized configuration hurts &lt;strong&gt;application portability&lt;/strong&gt;, because you must reconfigure for each injector.&lt;br /&gt;&lt;br /&gt;Configuration was left out because there's &lt;strong&gt;no consensus&lt;/strong&gt; on the best way to do it. Unlike annotations, each injector takes a distinct approach, each with relative strengths and weaknesses. For example, consider this (simplified) matrix:&lt;br /&gt;&lt;br /&gt;&lt;table bgcolor="#FFFFFF" border="1" cellpadding="3" cellspacing="0"&gt;&lt;tr&gt;&lt;th align="left"&gt;Injector&lt;/th&gt;&lt;th&gt;XML etc.&lt;/th&gt;&lt;th&gt;Code&lt;/th&gt;&lt;th&gt;Annotations&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spring&lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td align="center"&gt;&lt;font color="#999999"&gt;optional&lt;/font&gt;&lt;/td&gt;&lt;td align="center"&gt;&lt;font color="#999999"&gt;optional&lt;/font&gt;&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Guice&lt;/td&gt;&lt;td align="center"&gt; &lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://butterfly.jenkov.com/container/"&gt;Butterfly&lt;/a&gt;&lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td align="center"&gt; &lt;/td&gt;&lt;td align="center"&gt; &lt;/td&gt;&lt;td&gt;has its own DSL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=299"&gt;JSR 299&lt;/a&gt;&lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td align="center"&gt; &lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td&gt;plus classpath scanning&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PicoContainer&lt;/td&gt;&lt;td align="center"&gt; &lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td align="center"&gt;✔&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br&gt;&lt;hr width="25%" align="center"&gt;&lt;br&gt;&lt;br&gt;I'm excited about &lt;a href="http://code.google.com/p/atinject/"&gt;the new proposal&lt;/a&gt; because it's pragmatic. It paves the well-worn paths (the annotations), but permits innovation to foster elsewhere. Fantastic work guys!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-1955876021526227053?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/1955876021526227053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=1955876021526227053' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1955876021526227053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1955876021526227053'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/05/my-perspective-on-atinject.html' title='My perspective on Atinject'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-2704622874685621536</id><published>2009-05-04T00:17:00.000-07:00</published><updated>2009-05-04T00:49:15.875-07:00</updated><title type='text'>Java Minutiae - Reflex</title><content type='html'>&lt;strong&gt;Pop Quiz&lt;/strong&gt;&lt;br /&gt;The following is a method from a &lt;a href="http://harmony.apache.org/index.html"&gt;very decent implementation&lt;/a&gt; of Java SE. I've substituted &lt;i&gt;x&lt;/i&gt; and &lt;i&gt;y&lt;/i&gt; for the actual method name and parameter type. What are the values of &lt;i&gt;x&lt;/i&gt; and &lt;i&gt;y&lt;/i&gt; ?&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;public static boolean &lt;span id="blank"&gt;&lt;i&gt;x&lt;/i&gt;(&lt;i&gt;y&lt;/i&gt; z)&lt;/span&gt;&lt;span id="answer" style="display:none"&gt;&lt;strong&gt;isNaN&lt;/strong&gt;(&lt;strong&gt;float&lt;/strong&gt; z)&lt;/span&gt; {&lt;br /&gt;  return z != z;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;PS - it's a reasonable method. it may take you a few minutes to come up with the answer.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="#" onClick="document.getElementById('answer').style.display='inline'; document.getElementById('blank').style.display='none'; document.getElementById('why').style.visibility='visible'; return false;"&gt;Show Answer&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;span id="why" style="visibility: hidden"&gt;&lt;i&gt;x&lt;/i&gt; = isNaN, &lt;i&gt;y&lt;/i&gt; = float&lt;br /&gt;&lt;br /&gt;It turns out that &lt;code&gt;Float.NaN != Float.NaN&lt;/code&gt;. Weird! The same is true for &lt;code&gt;Double.NAN&lt;/code&gt;. Since they're the only values with this property, testing for a lack of reflexivity uniquely identifies these values.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-2704622874685621536?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/2704622874685621536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=2704622874685621536' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/2704622874685621536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/2704622874685621536'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/05/java-minutiae-reflex.html' title='Java Minutiae - Reflex'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-8143874390413199614</id><published>2009-04-30T20:17:00.000-07:00</published><updated>2009-04-30T21:17:22.060-07:00</updated><title type='text'>Some talks for your JavaOne Schedule</title><content type='html'>JavaOne is coming up, and now is the time to convince your boss to send you. You only need to learn a few productive tools for the conference to pay for itself. In addition to &lt;a href="http://publicobject.com/2009/04/upcoming-guice-talks.html"&gt;the Guice talk&lt;/a&gt;, here's some sessions I'm excited about...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;Developing LimeWire: Swing for the Masses&lt;/strong&gt;&lt;br /&gt;Use painters, AppFramework, XUL and even GlazedLists to create hot Swing apps.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Simply Sweet Components&lt;/strong&gt;&lt;br /&gt;How Component-oriented design dramatically simplifies UI development.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The Collections Connection&lt;/strong&gt;&lt;br /&gt;Philosophy behind the Java™ Collections Framework and Google Collections.&lt;/blockquote&gt;&lt;br /&gt;&lt;a href="http://java.sun.com/javaone/2009/registration.jsp"&gt;JavaOne registration&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-8143874390413199614?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/8143874390413199614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=8143874390413199614' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/8143874390413199614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/8143874390413199614'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/04/some-talks-for-your-javaone-schedule.html' title='Some talks for your JavaOne Schedule'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-761769967563295854</id><published>2009-04-21T10:15:00.000-07:00</published><updated>2009-04-21T10:44:50.111-07:00</updated><title type='text'>Two simple classes for text processing in Java</title><content type='html'>&lt;code&gt;FileCharSequence&lt;/code&gt; adapts a &lt;code&gt;java.io.File&lt;/code&gt; as a &lt;code&gt;CharSequence&lt;/code&gt; which has nice consequences. For example, you can run Java regular expressions directly against a File. And you can easily send part or all of a file to a &lt;code&gt;StringBuilder&lt;/code&gt; or &lt;code&gt;Writer&lt;/code&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;/**&lt;br /&gt; * Adapts a text file as a character sequence so that it can be directly&lt;br /&gt; * manipulated by regular expressions and other character utilities. The&lt;br /&gt; * file may be at most 2 GB in size and encoded with {@code ISO-8859-1};&lt;br /&gt; * otherwise behaviour is undefined.&lt;br /&gt; */&lt;br /&gt;public final class FileCharSequence implements CharSequence {&lt;br /&gt;  ...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;If you like this, feel free to use &lt;a href="http://code.google.com/p/publicobject/source/browse/trunk/src/com/publicobject/io/FileCharSequence.java"&gt;the code&lt;/a&gt; in your projects.&lt;br /&gt;&lt;br /&gt;I prefer to use Java for one-off text processing tools. Partly this is because that's what my development environment is already set up to do, and partly it's because I'm not very productive in Python. With that constraint, I've written &lt;code&gt;Strip.java&lt;/code&gt;. It uses &lt;code&gt;FileCharSequence&lt;/code&gt; behind-the-scenes to strip all occurrences of a regex from a file. It uses Java's regex syntax, and supports switches like &lt;code&gt;(?m)&lt;/code&gt; for multi-line regexes. Just like &lt;a href="http://publicobject.com/2008/08/ripjava-stream-manipulation-for-java.html"&gt;the Rip.java tool&lt;/a&gt;, it can be executed directly from your command line:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;jessewilson:~$ &lt;strong&gt;Strip.java&lt;/strong&gt;&lt;br /&gt;Usage: Strip &amp;lt;regex&amp;gt; [files]&lt;br /&gt;&lt;br /&gt;  regex: a Java regular expression, with groups&lt;br /&gt;  http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html&lt;br /&gt;         you can (parenthesize) groups&lt;br /&gt;         \s whitespace&lt;br /&gt;         \S non-whitespace&lt;br /&gt;         \w word characters&lt;br /&gt;         \W non-word&lt;br /&gt;&lt;br /&gt;  files: files to strip. These will be overwritten!&lt;br /&gt;&lt;br /&gt;flags:&lt;br /&gt;  --clober: overwrite the passed in files rather than creating new ones&lt;br /&gt;        -c:&lt;br /&gt;&lt;br /&gt;  Use 'single quotes' to prevent bash from interfering&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This code is also Apache-licensed for your enjoyment. Download &lt;a href="http://code.google.com/p/publicobject/source/browse/trunk/src/com/publicobject/io/Strip.java"&gt;Strip.java&lt;/a&gt;, make it executable (&lt;code&gt;chmod a+x Strip.java&lt;/code&gt;) and put it somewhere on your path!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-761769967563295854?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/761769967563295854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=761769967563295854' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/761769967563295854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/761769967563295854'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/04/two-simple-classes-for-text-processing.html' title='Two simple classes for text processing in Java'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-2909624350193966592</id><published>2009-04-20T17:33:00.000-07:00</published><updated>2009-04-20T17:56:40.097-07:00</updated><title type='text'>Upcoming Guice talks</title><content type='html'>&lt;a href="http://twitter.com/dhanji"&gt;Dhanji&lt;/a&gt; and I are doing some Guice talks over the next two months.&lt;br /&gt;&lt;br /&gt;First, we'll be presenting at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. This conference is fast, web-focused, and cutting edge. It's also affordable: $300 if you register before May 1.&lt;p&gt;&lt;blockquote&gt;&lt;strong&gt;Big Modular Java with Guice&lt;/strong&gt;&lt;br /&gt;Learn how Google uses the fast, lightweight Guice framework to power some of the largest and most complex applications in the world. Supporting scores of developers, and steep testing and scaling requirements for the web, Guice proves that there is still ample room for a simple, type-safe and dynamic programming model in Java. This session will serve as a simple introduction to Guice, its ecosystem and how we use it at Google.&lt;/blockquote&gt;&lt;p&gt;Then at &lt;a href="http://java.sun.com/javaone/2009/registration.jsp"&gt;JavaOne&lt;/a&gt;, I'll be providing a technical intro to Guice. It's a Friday afternoon time slot, so hopefully you're not too worn out to make the talk.&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;Introduction to Google Guice: Java is fun again!&lt;/strong&gt;&lt;br /&gt;Session TS-5434, Core Technology track&lt;br /&gt;Friday June 5 at 14:50&lt;br /&gt;&lt;br /&gt;Before Guice, the Java programming language subjected developers to a false dichotomy: &lt;br /&gt;&lt;li&gt;Use "new" to write concise but tightly coupled code. If you need more abstraction later on, you'll have to update all of the N callers.&lt;br /&gt;&lt;li&gt;Write a factory so you can easily change the implementation later on. You might end up doing unnecessary work, not to mention make your code harder to read.&lt;p&gt;Guice leverages recently added language features to enable the best of both words: abstraction without the boilerplate! Guice's @Inject is the new new. Start off with coupled and straightforward code. If you need more flexibility down the road, you can change your code in one place; you don't need to update N callers.&lt;p&gt;Jesse and Bob, each of whom have organized millions of lines of Google code, will compare factories and service locators to dependency injection, with and without Guice. Then, they'll show you how to use Guice to make your code more modular, readable, and testable than ever before. All you need is a working knowledge of the language.&lt;/blockquote&gt;&lt;p&gt;Immediately following the introductory talk, Dhanji Prasanna will be presenting Google open source development with Guice, GWT, and SiteBricks.&lt;p&gt;&lt;blockquote&gt;&lt;strong&gt;Building Enterprise Java™ Technology-Based Web Apps with Google Open-Source Technology&lt;/strong&gt;&lt;br /&gt;Session TS-4062&lt;br /&gt;Friday June 5 at 16:10&lt;br /&gt;&lt;br /&gt;Google open-source technologies bring a new perspective to enterprise Web applications. The company likes simple stuff that's easy to maintain and that works and scales REALLY well. It also believes that the Java™ platform is strong and thriving and can be as lightweight and competitive as other popular dynamic platforms. With the right approach.&lt;p&gt;This session explores how you can take away the pain of traditional enterprise development with Googley alternatives in your stack. Use Google Guice, the Google Web Toolkit, and SiteBricks to completely rethink how you write applications. These technologies all employ idiomatic Java programming language -- but in highly productive, novel ways -- and have produced enormous success in some of the largest and most complex applications ever built.&lt;p&gt;Take the simple back! The Googley way.&lt;/blockquote&gt;&lt;p&gt;Please come out! I'm particularly excited to get to spend some time with other developers. Mailing list discussions flow better for me when I can put a face to the names.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-2909624350193966592?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/2909624350193966592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=2909624350193966592' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/2909624350193966592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/2909624350193966592'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/04/upcoming-guice-talks.html' title='Upcoming Guice talks'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-4700337481671975658</id><published>2009-04-03T10:34:00.000-07:00</published><updated>2009-04-03T10:55:37.929-07:00</updated><title type='text'>Jesse and Kevin B help out with Java Posse #239</title><content type='html'>I love listening to The Java Posse. Back when &lt;a href="http://publicobject.com/2006/08/glazed-lists-on-java-posse-76.html"&gt;they mentioned Glazed Lists&lt;/a&gt; on episode 76, I was majorly psyched. I ran home and played the relevant clip for my wife, who's usually annoyed at the amount of time I spend programming,&lt;br /&gt;&lt;i&gt;"See Jodie? See, see? I feel so proud of myself, having been referenced on my favourite show! They'll know of Glazed Lists across seven continents! Yay!"&lt;/i&gt;&lt;br /&gt;Jodie, &lt;i&gt;"Wow, my hubby is &lt;strong&gt;Internet&lt;/strong&gt;-famous!"&lt;/i&gt; She was impressed, but only because I was. &lt;br /&gt;&lt;br /&gt;On Wednesday, I did even better - I got airtime on the Posse! &lt;a href="http://smallwig.blogspot.com/"&gt;Kevin B&lt;/a&gt; and myself got to discuss the news with Dick, Carl, Joe and Tor on &lt;a href="http://javaposse.com/index.php?post_id=450656"&gt;Episode 239&lt;/a&gt;. Everytime that I listen to the Posse, I always want to participate in the discussion. Well, I had a chance and it was a fairly lively episode.&lt;br /&gt;&lt;br /&gt;You can hear me giggling at the jokes the whole way through. I probably shouldn't have giggled so much, but it's a habit from the previous 238 episodes. Keep up the fantastic work Java Posse.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-4700337481671975658?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/4700337481671975658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=4700337481671975658' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4700337481671975658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4700337481671975658'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/04/jesse-and-kevin-b-help-out-with-java.html' title='Jesse and Kevin B help out with Java Posse #239'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-1624350315281810492</id><published>2009-03-07T08:38:00.000-08:00</published><updated>2009-03-07T09:19:13.842-08:00</updated><title type='text'>Read your address bar carefully</title><content type='html'>Internet addresses are no longer stuck with ASCII and English. If you're Greek, you can have a Greek domain name; if you're Japanese you can have a Japanese domain name. To make international characters work on the existing ASCII system, you &lt;a href="http://en.wikipedia.org/wiki/Internationalized_domain_name"&gt; encode the address&lt;/a&gt; in Punycode: &lt;br /&gt;&lt;blockquote&gt;As an example of how IDNA works, suppose the domain to be encoded is &lt;code&gt;Bücher.ch&lt;/code&gt; (“Bücher” is German for “books”, and .ch is the country domain for Switzerland). This has two labels, &lt;code&gt;Bücher&lt;/code&gt; and &lt;code&gt;ch&lt;/code&gt;. The second label is pure ASCII, and so is left unchanged. The first label is processed by Nameprep to give bücher, and then by Punycode to give &lt;code&gt;bcher-kva&lt;/code&gt;, and then has &lt;code&gt;xn--&lt;/code&gt; prepended to give &lt;code&gt;xn--bcher-kva&lt;/code&gt;. The final domain suitable for use with the DNS is therefore &lt;code&gt;xn--bcher-kva.ch&lt;/code&gt;.&lt;/blockquote&gt;&lt;br /&gt;To avoid spoofing addresses, browsers render the ugly Punycode version whenever there's an ambiguous character. This is necessary to differentiate &lt;code&gt;pаypal.com&lt;/code&gt; (where the first &lt;code&gt;a&lt;/code&gt; is replaced by a Cyrillic &lt;code&gt;а&lt;/code&gt;) from &lt;code&gt;paypal.com&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;http://com丿asp.com&lt;/h3&gt;&lt;br /&gt;I registered &lt;code&gt;xn--comasp-yz7i.com&lt;/code&gt;, the Punycoded form of &lt;code&gt;com丿asp.com&lt;/code&gt;. The fourth character isn't a slash &lt;code&gt;/&lt;/code&gt;, but the curlier Japanese character &lt;code&gt;丿&lt;/code&gt;. On current versions of Safari, this character lends itself to fun domain spoofing.&lt;blockquote align="center"&gt;&lt;a href="http://www.microsoft.com丿asp.com/windows7/linux_support.html"&gt;&lt;img src="http://publicobject.com/uploaded_images/Picture-13-756505.png" width="500" height="400"&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;This probably isn't good enough to fool a seasoned software developer. But could it fool your mom?&lt;br /&gt;&lt;br /&gt;&lt;i&gt;PS: I've already reported the bug to Apple. If your app displays URLs to users, this is something you may need to consider as well.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-1624350315281810492?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/1624350315281810492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=1624350315281810492' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1624350315281810492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1624350315281810492'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/03/read-your-address-bar-carefully.html' title='Read your address bar carefully'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-5156849111674401680</id><published>2009-02-18T18:57:00.000-08:00</published><updated>2009-02-18T19:27:43.515-08:00</updated><title type='text'>Preprocessing .java with Munge</title><content type='html'>In the rare situation that you need to preprocess &lt;code&gt;.java&lt;/code&gt; files, Munge is a pretty decent tool for getting it done. From &lt;a href="http://weblogs.java.net/blog/tball/archive/2006/09/munge_swings_se.html"&gt;Tom Ball's blog&lt;/a&gt;,&lt;br /&gt;&lt;blockquote&gt;So a combination preprocessor and string translator, &lt;a href="http://weblogs.java.net/blog/tball/archive/munge/doc/Munge.html"&gt;Munge&lt;/a&gt;, was created to address [supporting Java 1.1 and Java 2] (&lt;a href="http://weblogs.java.net/blog/tball/archive/munge/Munge.java"&gt;source&lt;/a&gt;). Since its requirements were that it be small, fast and require no maintenance (it wasn't a product, after all), it purposely has no features that weren't needed by the team. It won't have your favorite cpp or sed feature, but what it did, it did quickly and correctly. It wasn't open-source then, but if you wanted a feature you were handed the source and told to have fun.&lt;/blockquote&gt;&lt;br /&gt;We're using Munge in Guice to support both AOP and non-AOP releases. AOP is awesome, but it requires bytecode generation which isn't available on Android yet. To support stripping AOP out, our source files now include preprocessor instructions:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;public interface Binder {&lt;br /&gt;&lt;br /&gt;  /*if[AOP]*/&lt;br /&gt;  /**&lt;br /&gt;   * Binds a method interceptor to methods matched by class and method&lt;br /&gt;   * matchers.&lt;br /&gt;   *&lt;br /&gt;   * @param classMatcher matches classes the interceptor should apply to. For&lt;br /&gt;   *     example: {@code only(Runnable.class)}.&lt;br /&gt;   * @param methodMatcher matches methods the interceptor should apply to. For&lt;br /&gt;   *     example: {@code annotatedWith(Transactional.class)}.&lt;br /&gt;   * @param interceptors to bind&lt;br /&gt;   */&lt;br /&gt;  void bindInterceptor(Matcher&amp;lt;? super Class&amp;lt;?&amp;gt;&amp;gt; classMatcher,&lt;br /&gt;      Matcher&amp;lt;? super Method&amp;gt; methodMatcher, MethodInterceptor... interceptors);&lt;br /&gt;  /*end[AOP]*/&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Binds a scope to an annotation.&lt;br /&gt;   */&lt;br /&gt;  void bindScope(Class&amp;lt;? extends Annotation&amp;gt; annotationType, Scope scope);&lt;br /&gt;&lt;br /&gt;  ...&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I patched Munge to be a bit more careful with C-style comments (&lt;code&gt;/*&lt;/code&gt;) inside end-of-line comments and strings. This is necessary to handle calls like &lt;code&gt;filter("/*")&lt;/code&gt; and &lt;code&gt;serve("/*")&lt;/code&gt; in our updated servlet package.&lt;br /&gt;&lt;br /&gt;Ours also has an Ant task to munge the entire project in one go:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;  &amp;lt;target name="no_aop"&lt;br /&gt;          description="Create a copy of the Guice source that doesn't do bytecode generation."&amp;gt;&lt;br /&gt;    &amp;lt;taskdef name="munge" classname="MungeTask" classpath="lib/build/munge.jar"/&amp;gt;&lt;br /&gt;    &amp;lt;mkdir dir="build/no_aop"/&amp;gt;&lt;br /&gt;    &amp;lt;munge todir="build/no_aop"&amp;gt;&lt;br /&gt;      &amp;lt;fileset dir="." excludes="build/**/*"/&amp;gt;&lt;br /&gt;      &amp;lt;arg value="-DNO_AOP" /&amp;gt;&lt;br /&gt;    &amp;lt;/munge&amp;gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;If you're preprocessing some &lt;code&gt;.java&lt;/code&gt; files and can use these features, help yourself to our custom &lt;a href="http://google-guice.googlecode.com/svn/trunk/lib/build/munge.jar"&gt;munge.jar&lt;/a&gt;. The jar includes both source and classfiles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-5156849111674401680?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/5156849111674401680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=5156849111674401680' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/5156849111674401680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/5156849111674401680'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/02/preprocessing-java-with-munge.html' title='Preprocessing .java with Munge'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-4481430839372911050</id><published>2009-01-01T21:54:00.000-08:00</published><updated>2009-01-01T22:53:42.521-08:00</updated><title type='text'>Always use jarjar to package implementation dependencies</title><content type='html'>&lt;a href="http://code.google.com/p/jarjar/"&gt;jarjar&lt;/a&gt; is a sweet Java packaging tool that allows you to embed one &lt;code&gt;.jar&lt;/code&gt; file in another. But rather than just smashing the jars together in one big archive, jarjar renames the embedded &lt;code&gt;.jar&lt;/code&gt;'s classes so that they live in the main jar's namespace. For example, Guice's &lt;code&gt;ProxyFactory.java&lt;/code&gt; file has an impressive collection of imports:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;package com.google.inject;&lt;br /&gt;&lt;br /&gt;import com.google.common.collect.ImmutableList;&lt;br /&gt;import com.google.common.collect.ImmutableMap;&lt;br /&gt;import com.google.common.collect.Lists;&lt;br /&gt;import com.google.common.collect.Maps;&lt;br /&gt;import com.google.inject.internal.*;&lt;br /&gt;import java.lang.reflect.*;&lt;br /&gt;import java.util.*;&lt;br /&gt;import net.sf.cglib.proxy.Callback;&lt;br /&gt;import net.sf.cglib.proxy.CallbackFilter;&lt;br /&gt;import net.sf.cglib.proxy.Enhancer;&lt;br /&gt;import net.sf.cglib.proxy.MethodProxy;&lt;br /&gt;import net.sf.cglib.reflect.FastClass;&lt;br /&gt;import net.sf.cglib.reflect.FastConstructor;&lt;br /&gt;&lt;br /&gt;class ProxyFactory implements ConstructionProxyFactory {&lt;br /&gt;  ...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;These imports include classes from &lt;a href="http://cglib.sourceforge.net/"&gt;net.sf.cglib&lt;/a&gt; and &lt;a href="http://code.google.com/p/google-collections/"&gt;com.googe.common.collect&lt;/a&gt;. But when we package it up with jarjar, everything gets prefixed with the Guice package name: &lt;strong&gt;com/google/inject&lt;/strong&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;     0 Thu Jan 01 22:13:36 PST 2009 META-INF/&lt;br /&gt;  1726 Thu Jan 01 22:13:34 PST 2009 META-INF/MANIFEST.MF&lt;br /&gt; 11357 Sun May 25 20:34:04 PDT 2008 LICENSE&lt;br /&gt;   101 Sun May 25 20:34:04 PDT 2008 NOTICE&lt;br /&gt;  5975 Thu Jan 01 22:13:20 PST 2009 com/google/inject/AbstractModule.class&lt;br /&gt;  2466 Thu Jan 01 22:13:20 PST 2009 com/google/inject/Binder.class&lt;br /&gt;   806 Thu Jan 01 22:13:20 PST 2009 com/google/inject/Binding.class&lt;br /&gt;   414 Thu Jan 01 22:13:22 PST 2009 com/google/inject/BindingAnnotation.class&lt;br /&gt;   ...&lt;br /&gt;   136 Sun May 25 20:34:04 PDT 2008 com/google/inject/internal/cglib/proxy/Callback.class&lt;br /&gt;   238 Sun May 25 20:34:04 PDT 2008 com/google/inject/internal/cglib/proxy/CallbackFilter.class&lt;br /&gt; 28315 Sun May 25 20:34:04 PDT 2008 com/google/inject/internal/cglib/proxy/Enhancer.class&lt;br /&gt;  5712 Sun May 25 20:34:04 PDT 2008 com/google/inject/internal/cglib/proxy/MethodProxy.class&lt;br /&gt;  5535 Sun May 25 20:34:04 PDT 2008 com/google/inject/internal/cglib/reflect/FastClass.class&lt;br /&gt;  1642 Sun May 25 20:34:04 PDT 2008 com/google/inject/internal/cglib/reflect/FastConstructor.class&lt;br /&gt;  ...&lt;br /&gt;  8144 Sat Nov 29 14:11:22 PST 2008 com/google/inject/internal/collect/ImmutableList.class&lt;br /&gt;  9826 Sat Nov 29 14:11:26 PST 2008 com/google/inject/internal/collect/ImmutableMap.class&lt;br /&gt;  6026 Sat Nov 29 14:11:24 PST 2008 com/google/inject/internal/collect/Lists.class&lt;br /&gt; 12551 Sat Nov 29 14:11:26 PST 2008 com/google/inject/internal/collect/Maps.class&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;By using &lt;strong&gt;jarjar&lt;/strong&gt;, Guice encapsulates these library dependencies. This is fantastic! Many problems are avoided by encapsulating the library dependency:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Guice users don't need to tell their classpath, IDE or &lt;code&gt;build.xml&lt;/code&gt; files about cglib or Google Collections.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Other versions of the libraries won't conflict with the Guice version. We can ship &lt;strong&gt;one&lt;/strong&gt; binary and support users of either &lt;i&gt;extremely old&lt;/i&gt; or &lt;i&gt;extremely new&lt;/i&gt; versions of cglib. Even if cglib broke compatibility every release (it doesn't), we aren't impacted.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;We can freely change our own libraries. Should we add a dependency on &lt;a href="http://paranamer.codehaus.org/"&gt;paranamer&lt;/a&gt; in a future release, our users don't need to reconfigure their build scripts.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Most importantly,&lt;/strong&gt; we can patch the libraries to fit our needs. If we want a special build of google-collections that includes our own hacks and tweaks, that's just fine. Our build doesn't even need to be compatible with the public version.&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Standard jars for API dependencies&lt;/h3&gt;&lt;br /&gt;Guice's dependency on &lt;a href="http://aopalliance.sourceforge.net/"&gt;aopalliance&lt;/a&gt; &lt;i&gt;doesn't&lt;/i&gt; use jarjar. Guice users implement the aopalliance interfaces, so the version independence and encapsulation offered by jarjar doesn't make much sense.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-4481430839372911050?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/4481430839372911050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=4481430839372911050' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4481430839372911050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/4481430839372911050'/><link rel='alternate' type='text/html' href='http://publicobject.com/2009/01/always-use-jarjar-to-package.html' title='Always use jarjar to package implementation dependencies'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-9113271604663220755</id><published>2008-11-20T22:26:00.000-08:00</published><updated>2008-11-20T22:37:06.465-08:00</updated><title type='text'>howmanyspacesafteraperiod.com</title><content type='html'>Inspired by the URL-as-question meme sites &lt;a href="http://hasthelargehadroncolliderdestroyedtheworldyet.com/"&gt;http://has the large hadron collider destroyed the world yet.com&lt;/a&gt; and &lt;a href="http://shouldiusetablesforlayout.com/"&gt;http://should I use tables for layout.com&lt;/a&gt;,  I present &lt;a href="http://howmanyspacesafteraperiod.com"&gt;http://how many spaces after a period.com&lt;/a&gt;:&lt;br /&gt;&lt;blockquote align="center"&gt;&lt;a href="http://howmanyspacesafteraperiod.com"&gt;&lt;img width="400" height="313" src="http://publicobject.com/uploaded_images/Picture-2-735644.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-9113271604663220755?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/9113271604663220755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=9113271604663220755' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/9113271604663220755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/9113271604663220755'/><link rel='alternate' type='text/html' href='http://publicobject.com/2008/11/howmanyspacesafteraperiodcom.html' title='howmanyspacesafteraperiod.com'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-1088854670219627594</id><published>2008-11-17T08:32:00.000-08:00</published><updated>2008-11-17T09:55:27.017-08:00</updated><title type='text'>Audible on Android (and other devices)</title><content type='html'>I love my new &lt;a href="http://www.t-mobileg1.com/"&gt;G1&lt;/a&gt;, but it doesn't work with &lt;a href="http://www.audible.com/"&gt;Audible&lt;/a&gt; yet. Fortunately, I have a workaround. This guide describes how to get audiobooks onto a G1. You'll need a Mac and $40 worth of software.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Download and install &lt;a href="http://www.tune4mac.com/"&gt;Tune4Mac&lt;/a&gt;.&lt;/strong&gt; This app creates a virtual CD burner on your Mac, so when you tell iTunes to burn a CD, you don't actually need a blank CD-R. It's a clever hack, and the software works as promised. There's a &lt;a href="http://www.tune4win.com/"&gt;Windows version&lt;/a&gt;, but I haven't tried it.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="http://www.tune4mac.com/order.html"&gt;Register Tune4Mac&lt;/a&gt;.&lt;/strong&gt; It's $39.95. You'll get the license key to your email immediately, paste that in the app's Registration dialog.&lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="286" src="http://publicobject.com/uploaded_images/registration-731330.png" &gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Configure AAC output in Tune4Mac.&lt;/strong&gt; Tune4Mac automatically encodes audio to either MP3 or AAC. I tried MP3 encoding, and it was flaky, but AAC encoding worked just fine. Save this change by closing the dialog.&lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="275" src="http://publicobject.com/uploaded_images/aac-733199.png" &gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Add audiobooks to iTunes.&lt;/strong&gt; Purchase DRM-protected books from &lt;a href="http://www.audible.com/"&gt;Audible.com&lt;/a&gt;. If this is your first time using Audible, choose format #4, a high quality format that works with iTunes.&lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="273" src="http://publicobject.com/uploaded_images/audible-780768.png" &gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Create a playlist in iTunes.&lt;/strong&gt; iTunes burns CDs using playlists, and we're going to be burning a virtual CD. I used a different playlist for each part of my two-part audiobook.&lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="245" src="http://publicobject.com/uploaded_images/playlist-754494.png" &gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Prepare the fake burn.&lt;/strong&gt; Click the 'Burn Disc' button in the bottom right corner of the iTunes app. Select &lt;code&gt;Tune4Mac Virtual CDRW&lt;/code&gt;, &lt;code&gt;Maximum Possible&lt;/code&gt;, &lt;code&gt;Audio CD&lt;/code&gt;, &lt;code&gt;none&lt;/code&gt; and &lt;code&gt;Include CD Text&lt;/code&gt;. Click burn.&lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="264" src="http://publicobject.com/uploaded_images/burndisc-702438.png" &gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Burn fake CDs.&lt;/strong&gt; Click 'Burn' on the dialog, and then &lt;code&gt;Audio CDs&lt;/code&gt; on the dialog that follows. It took an hour for my computer to burn all the virtual CDs for an entire book. During this time, Tune4Mac automatically cycles fake blank CDs so you can go grab a coffee.&lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="180" src="http://publicobject.com/uploaded_images/audiocds-751133.png" /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Use Finder to transfer the book to your device.&lt;/strong&gt; I opened the &lt;code&gt;Documents&lt;/code&gt; folder, and then the &lt;code&gt;Tune4Mac&lt;/code&gt; folder to find my audiobook file. I plugged my device into my Mac, causing an icon for it to show up in the Finder. I dragged the &lt;code&gt;.m4a&lt;/code&gt; file to this icon to transfer the book. &lt;br /&gt;&lt;blockquote&gt;&lt;img align="center" width="400" height="194" src="http://publicobject.com/uploaded_images/finder-781780.png" /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Eject the device.&lt;/strong&gt; In the Finder, click the device's eject icon before detaching it. Otherwise the transfer might not finish properly.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Enjoy!&lt;/strong&gt; You can now enjoy audiobooks on your device. Unfortunately, some devices don't bookmark audiobooks, so you'll need to remember your place when you stop listening.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;font size="-1"&gt;Disclaimer: I admit that this process is painful and expensive. Hopefully Audible follows Amazon's lead and makes DRM-free audiobooks available for purchase. That way, Audible's huge library will be available to a larger audience.&lt;/font&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-1088854670219627594?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/1088854670219627594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=1088854670219627594' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1088854670219627594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/1088854670219627594'/><link rel='alternate' type='text/html' href='http://publicobject.com/2008/11/audible-on-android-and-other-devices.html' title='Audible on Android (and other devices)'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8675640.post-2599431944010791111</id><published>2008-11-15T01:32:00.000-08:00</published><updated>2008-11-15T02:23:16.543-08:00</updated><title type='text'>Guice punches erasure in the face!</title><content type='html'>&lt;a href="http://java.sun.com/docs/books/tutorial/java/generics/erasure.html"&gt;Java 5 Type Erasure&lt;/a&gt; is frustrating. I'm coding along, enjoying the glorious type safety of generics. And then I try to do a little more with the &lt;code&gt;T&lt;/code&gt;s, and erasure shows up, &lt;i&gt;"You can't do that!"&lt;/i&gt; I can't test an object if it really is a &lt;code&gt;T&lt;/code&gt;. I can't inspect &lt;code&gt;T.class&lt;/code&gt; using reflection. And I certainly can't new up a &lt;code&gt;T&lt;/code&gt;. Yuck.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;We're in a unique situation with Guice.&lt;/strong&gt; Its type literals and injection points have complete generic information. It can follow long chains of type variables throughout an object model. In my app, I've got a &lt;code&gt;Robot&amp;lt;T&amp;gt;&lt;/code&gt; that injects a &lt;code&gt;Claw&amp;lt;T&amp;gt;&lt;/code&gt;. When I request a &lt;code&gt;Robot&amp;lt;Adamantium&amp;gt;&lt;/code&gt;, Guice knows to find an adamantium claw.&lt;br /&gt;&lt;br /&gt;And now, this type information is available to application code. I can write a &lt;code&gt;Claw&amp;lt;T&amp;gt;&lt;/code&gt; class that actually knows what &lt;code&gt;T&lt;/code&gt; is at runtime!&lt;br /&gt;&lt;br /&gt;Consider &lt;code&gt; GuardingList&amp;lt;T&amp;gt;&lt;/code&gt;, which enforces type safety &lt;i&gt;at runtime&lt;/i&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;class GuardingList&amp;lt;T&amp;gt; extends AbstractList&amp;lt;T&amp;gt; {&lt;br /&gt;  private final TypeLiteral&amp;lt;T&amp;gt; elementType;&lt;br /&gt;  private final ArrayList&amp;lt;T&amp;gt; delegate = new ArrayList&amp;lt;T&amp;gt;();&lt;br /&gt;&lt;br /&gt;  @Inject&lt;br /&gt;  GuardingList(TypeLiteral&amp;lt;T&amp;gt; elementType) {&lt;br /&gt;    this.elementType = elementType;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean add(T t) {&lt;br /&gt;    checkArgument(elementType.getRawType().isInstance(t),&lt;br /&gt;        "Cannot add %s which is not of type %s", t, elementType);&lt;br /&gt;    return delegate.add(t);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public T get(int i) {&lt;br /&gt;    return delegate.get(i);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int size() {&lt;br /&gt;    return delegate.size();&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;When injected, Guice applies its type knowledge to inject the correct &lt;code&gt;TypeLiteral&amp;lt;T&amp;gt;&lt;/code&gt;. The &lt;code&gt;GuardingList&lt;/code&gt; blows up when I add an invalid element:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;  public static void main(String[] args) {&lt;br /&gt;    Injector injector = Guice.createInjector();&lt;br /&gt;&lt;br /&gt;    List&amp;lt;String&amp;gt; listOfString = injector.getInstance(&lt;br /&gt;        new Key&amp;lt;GuardingList&amp;lt;String&amp;gt;&amp;gt;() {});&lt;br /&gt;    listOfString.add("A");&lt;br /&gt;    listOfString.add("B");&lt;br /&gt;&lt;br /&gt;    /* totally unsafe, but this compiles and runs */   &lt;br /&gt;    List&amp;lt;Object&amp;gt; rawList = (List) listOfString;&lt;br /&gt;&lt;br /&gt;    /* throws an IllegalArgumentException, since the GuardingList&lt;br /&gt;        knows that its elements must be Strings */&lt;br /&gt;    rawList.add(666); &lt;br /&gt;  }&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;Types are the natural currency of Java.&lt;/strong&gt; Erasure is frustrating 'cause it takes them away from you at runtime. And now Guice can give 'em back.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/google-guice/"&gt;Reify today.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8675640-2599431944010791111?l=publicobject.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/2599431944010791111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=8675640&amp;postID=2599431944010791111' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/2599431944010791111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8675640/posts/default/2599431944010791111'/><link rel='alternate' type='text/html' href='http://publicobject.com/2008/11/guice-punches-erasure-in-face.html' title='Guice punches erasure in the face!'/><author><name>swankjesse</name><uri>http://www.blogger.com/profile/04905794974441087900</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13630639510779968923'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></entry></feed>