<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-18170508</id><updated>2012-01-21T18:20:48.021-08:00</updated><title type='text'>Tuple23</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.tuple23.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>34</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18170508.post-8117508096381929076</id><published>2011-02-03T18:01:00.000-08:00</published><updated>2011-03-28T11:57:15.109-07:00</updated><title type='text'>Scala's upcoming dynamic capabilities</title><content type='html'>I was surprised to see the Scala team check in a new "Dynamic" trait &lt;a href="https://lampsvn.epfl.ch/trac/scala/changeset/23993"&gt;into Scala trunk&lt;/a&gt; recently. &amp;nbsp;Once this trait is mixed in to your class, any unresolved method calls are passed to an invokeDynamic() method, much like Ruby's method_missing. &lt;br /&gt;&lt;br /&gt;I've been thinking about this a lot, and I see three decent reasons for the inclusion of the Dynamic trait:&lt;br /&gt;1. Integration with dynamic languages on the JVM.&lt;br /&gt;2. DSLs for accessing data where there's already no type safety, ie JSON and &lt;a href="http://pastie.org/1469213"&gt;XML&lt;/a&gt;&amp;nbsp;(written by @jorgeortiz85, I think)&lt;br /&gt;3. DSL for reflection. Reflection libraries are ridiculously verbose, and like JSON/XML/etc libraries, offer little static typing benefits anyway.&lt;br /&gt;&lt;br /&gt;I think #1 is very convincing. &amp;nbsp;LinkedIn and their &lt;a href="http://www.infoq.com/articles/linkedin-scala-jruby-voldemort"&gt;LinkedIn Signal&lt;/a&gt; is one of the high-profile usages of Scala in industry, and it is a mixed Scala/JRuby project. &amp;nbsp;And why the heck not? &amp;nbsp;I'm very much warming to the idea that there is no &lt;a href="http://www.jroller.com/scolebourne/entry/the_next_big_jvm_language1"&gt;Next Big Language&lt;/a&gt;, and programmers of different mindsets will be able to work together with the best tools possible.&lt;br /&gt;&lt;br /&gt;Using the Dynamic trait is very easy, and really fun. &amp;nbsp;I thought I'd try hooking up Scala to Ruby using Dynamic, JRuby, and the Java Scripting Engine (JSR 223). &amp;nbsp;I was really pleased with how easy it was. &amp;nbsp;Here's some Ruby:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=3VMF2W3c" style="border: none; height: 220px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;With a little setup (installing JRuby to get the "jruby" scripting engine and getting Scala trunk running), I had this simple Scala class:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=DXSCNXv5" style="border: none; height: 450px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;The Ruby above can be annotated with type information, allowing jrubyc to compile down to &lt;a href="http://tommy.chheng.com/index.php/2010/06/call-a-jruby-method-from-java/"&gt;normal old class&lt;/a&gt; files with complete type information. &amp;nbsp;In that case, we'd only need Dynamic for sugaring calls to "dynamic finders" which aren't declared in the class at all. &amp;nbsp;I imagine the situation is similar for other dynamic languages on the JVM. &amp;nbsp;I have to wonder why dynamic invocation would be preferable to calling static bindings of these dynamic classes. &amp;nbsp;I would love to learn more about how this will all work out in practice.&lt;br /&gt;&lt;br /&gt;I have no information on this whatsoever, but from what I can tell this would be in Scala 2.9, which is slated for release in "&lt;a href="https://groups.google.com/forum/#!msg/scala-ide-dev/122UMdfctlM/kpPr8j2-0uoJ"&gt;weeks not months&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 3/28/2011: &amp;nbsp;&lt;/b&gt;For Scala 2.9&lt;b&gt;,&amp;nbsp;&lt;/b&gt;This method is now called "applyDynamic", but is only available with &lt;a href="http://groups.google.com/group/scala-language/msg/48db8af15d5477e5"&gt;the&amp;nbsp;-Xexperimental flag&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-8117508096381929076?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/8117508096381929076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=8117508096381929076' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/8117508096381929076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/8117508096381929076'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2011/02/scalas-upcoming-dynamic-capabilities.html' title='Scala&apos;s upcoming dynamic capabilities'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-1798035885680233822</id><published>2010-11-20T18:41:00.000-08:00</published><updated>2010-11-25T09:57:14.574-08:00</updated><title type='text'>"Intro to Scala for Java Programmers": slides, code, and links</title><content type='html'>Last week, I presented a talk titled "An Introduction to Scala for Java Programmers". &amp;nbsp;I had a lot of fun making it, and I learned a ton. &amp;nbsp;I thought it was interesting that the more I learned, the more I liked Scala. &amp;nbsp;This is certainly not always true of technologies that look good at first!&lt;br /&gt;&lt;br /&gt;Here's the slides. &amp;nbsp;They're probably pretty reliant on the speaking that typically goes with them, but maybe you will see something interesting.&lt;br /&gt;&lt;div id="__ss_5825339" style="width: 425px;"&gt;&lt;span style="display: block; margin-bottom: 4px; margin-left: 0px; margin-right: 0px; margin-top: 12px;"&gt;&lt;/span&gt;&lt;strong style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/adamrabung/introduction-to-scala-for-java-programmers" title="Introduction to Scala for Java Programmers"&gt;Introduction to Scala for Java Programmers&lt;/a&gt;&lt;/strong&gt;&lt;object height="355" id="__sse5825339" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=scalatalk-101118113115-phpapp02&amp;stripped_title=introduction-to-scala-for-java-programmers&amp;userName=adamrabung" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5825339" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=scalatalk-101118113115-phpapp02&amp;stripped_title=introduction-to-scala-for-java-programmers&amp;userName=adamrabung" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0 12px;"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/573568/talk/talk.zip"&gt;Here's the code&lt;/a&gt; I used to develop the slides. &amp;nbsp;It's in the form of an Eclipse workspace. &amp;nbsp;To use it, you'll need the &lt;a href="http://www.scala-ide.org/"&gt;Scala plugin&lt;/a&gt; installed on Eclipse. &amp;nbsp;Unfortunately, you'll need to use Eclipse 3.5 (Galileo) instead of the latest. &amp;nbsp;Once it's installed, make sure you activate the Scala perspective, and import the sample code using File...Import...Existing Project Into Workspace, and use "Select Archive File" to import talk.zip. &amp;nbsp;The code is a downright odd collection of snippets, but I suspect it would be interesting to play with if you were curious about Scala.&lt;br /&gt;&lt;br /&gt;Finally, I wanted to give better credit for some of the ideas and samples in the slides.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;3 interesting uses of traits: lifted from this &lt;a href="http://lalitpant.blogspot.com/2008/07/traits-in-scala-powerful-design-tool.html"&gt;awesome article&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://lalitpant.blogspot.com/2008/07/traits-in-scala-powerful-design-tool.html"&gt;&lt;/a&gt;Actors: inspired by this &lt;a href="http://java.dzone.com/articles/scala-threadless-concurrent"&gt;great intro&lt;/a&gt; on Actors&amp;nbsp;&lt;/li&gt;&lt;li&gt;As useful as named parameters and default values are, I didn't have a good example to illustrate them until I found this &lt;a href="http://www.artima.com/scalazine/articles/named_and_default_parameters_in_scala.html"&gt;intro&lt;/a&gt; on Artima&lt;/li&gt;&lt;li&gt;I think the format of the slides was guided by this &lt;a href="http://www.scala-lang.org/node/4960"&gt;article&lt;/a&gt; on combining OO and functional principles.&lt;/li&gt;&lt;li&gt;Many times, I ended up referring back to &lt;a href="http://www.amazon.com/Programming-Scala-Comprehensive-Step---step/dp/0981531601/ref=sr_1_1?ie=UTF8&amp;amp;qid=1290307144&amp;amp;sr=8-1"&gt;Programming in Scala&lt;/a&gt; for clarity. &amp;nbsp;It's a great general-purpose programming book.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;Update: &lt;/b&gt;Some people have asked for a downloadable pdf - &lt;a href="http://dl.dropbox.com/u/573568/talk/ScalaTalk.pdf"&gt;here it is&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-1798035885680233822?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/1798035885680233822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=1798035885680233822' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1798035885680233822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1798035885680233822'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/11/intro-to-scala-for-java-programmers.html' title='&quot;Intro to Scala for Java Programmers&quot;: slides, code, and links'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-7392673624481048888</id><published>2010-10-26T09:06:00.000-07:00</published><updated>2010-10-28T11:08:46.331-07:00</updated><title type='text'>3 easy wins using Google Guava</title><content type='html'>Google Guava used to be known as Google Collections. &amp;nbsp;It is a large set of utility methods used within Google. &amp;nbsp;It aims to help you create concise and easy-to-read code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Concise collection initialization&lt;/b&gt; - No example of Java being overly verbose is complete without showing a repetitive and noisy constructor like this:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=RbNzWJq1" style="border: none; height: 60px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Java 7 intends to introduce a "diamond operator" which allows the code to be converted to this:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=3z59t4Br" style="border: none; height: 60px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;This kind of change probably won't prevent any bugs, but in my opinion it greatly reduces code "noise". &amp;nbsp;Noise does not matter in a single-line example, but makes a big difference when multiplied across an entire system.&lt;br /&gt;&lt;br /&gt;Google Guava provides similar functionality, today, and it works all the way back to Java 5. &amp;nbsp;It takes advantage of one of the few places Java does infer types: method return values.&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=nNtPUvLk" style="border: none; height: 60px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;Here, newHashMap is a static method on com.google.common.collect.Maps, with a static import. &amp;nbsp;It gets better, Guava can also be used to initialize collections with values:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=f6LTf8R5" style="border: none; height: 60px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;java.util.Arrays.asList does something similar, but is actually immutable. &amp;nbsp;In combination with other techniques (many from Guava), type inference for collections and easy collection initialization can really clean up your code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Multimap&lt;/b&gt; - How often are the values in your map actually a collection? &amp;nbsp;Imagine taking a group of people and grouping these people by last name using a Map.&lt;br /&gt;&lt;br /&gt;Current way:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=1HbQvFDk" style="border: none; height: 250px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Using Multimap:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=pSt4dLbr" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. One-liners&lt;/b&gt;&lt;br /&gt;Here's a small sampling of clever utility methods provided:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=u5d6BJn2" style="border:none;width:100%;height=600px"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;I've got to stop here, or I'll never finish.  I have only covered a few of the classes I really love, &amp;nbsp;honorable mention goes to:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/BiMap.html"&gt;BiMap&lt;/a&gt; - Easily create the inverse of your map (keys become values and values become keys)&lt;/li&gt;&lt;li&gt;&lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Ordering.html"&gt;Ordering&lt;/a&gt; - Lots of nice extensions to Comparator&lt;/li&gt;&lt;li&gt;&lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multiset.html"&gt;MultiSet&lt;/a&gt; - A set that keeps count of duplicates&lt;/li&gt;&lt;li&gt;&lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/base/Predicate.html"&gt;Predicates&lt;/a&gt; and &lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/base/Function.html"&gt;Functions&lt;/a&gt; - reusable objects for filtering and transforming your collections&lt;/li&gt;&lt;li&gt;&lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/AbstractIterator.html"&gt;AbstractIterator&lt;/a&gt; - Writing your own iterator is annoyingly tricky - this can really help&lt;/li&gt;&lt;li&gt;&lt;a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ForwardingCollection.html"&gt;Forwarding Collections&lt;/a&gt; - Makes it easy to write your collection classes by delegating to existing collections classes (w/o boilerplate)&lt;/li&gt;&lt;/ul&gt;There's also a huge portion of the library I don't know yet, and really want to investigate:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;MapMaker - Factory for producing maps for caches - makes a very tricky job easier.&lt;/li&gt;&lt;li&gt;Immutables - I'm a big fan of immutability, but haven't investigated Guava's extensive support for it yet&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-7392673624481048888?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/7392673624481048888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=7392673624481048888' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7392673624481048888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7392673624481048888'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/10/3-easy-wins-using-google-guava.html' title='3 easy wins using Google Guava'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-7627669349044723774</id><published>2010-10-22T12:05:00.000-07:00</published><updated>2011-08-17T09:00:44.224-07:00</updated><title type='text'>Scala's Option will save you from the most common cause of NullPointerException</title><content type='html'>A while back, Cedric Beust claimed &lt;a href="http://beust.com/weblog/2010/07/28/why-scalas-option-and-haskells-maybe-types-wont-save-you-from-null/"&gt;"Scala’s “Option” and Haskell’s “Maybe” types won’t save you from null"&lt;/a&gt;. &amp;nbsp;He's rightly convinced that Option is not a silver bullet for unexpectedly referencing null values at runtime. &amp;nbsp;However, &amp;nbsp;I believe there are "Good" NullPointerExceptions(NPE) and "Bad". &amp;nbsp;Option goes very, very far in saving you from "Bad" NPEs by enlisting the compilers help in tracking what is intended to be optional.&lt;br /&gt;&lt;br /&gt;I believe there are two very different cases of NullPointerException:&lt;br /&gt;"Bad" - The code &lt;b&gt;incorrectly&lt;/b&gt; assumes the value is guaranteed to be set, but the value is null.&lt;br /&gt;person.getPreferredTheme().getBackgoundColor();&lt;br /&gt;In this case "getPreferredTheme" is optional, but the programmer accesses it as if it will never be null in the current context.  This is programmer error, due to the fact that the developer was unaware/not caring the value can sometimes be null.  This is class of NPE I feel is the most common, and I believe the Option "pattern" can greatly, if not completely, reduce.&lt;br /&gt;&lt;br /&gt;"Good" - The code &lt;b&gt;correctly&lt;/b&gt; assumes the value is guaranteed to be set, but the value is null.&lt;br /&gt;manager.getCompany().getName()&lt;br /&gt;In this case, getCompany is designed to be set on a manager object.   In my opinion, the developer should NOT try to accommodate getCompany returning null if it is specified that it never will.  In the spirit of failing fast, the user should boldly use the object as it's specified.&lt;br /&gt;&lt;br /&gt;In both Good and Bad scenarios, how was it specified that getPreferredTheme was optional and getCompany was required?  In Java, I've seen a few approaches:&lt;br /&gt;&lt;br /&gt;1. Sheer mental horsepower and subjective judgement.  "Preferred Theme sounds pretty wishy washy to me, I better check for null".  If you're not sure, check the javadoc, source, database schema, and any number of artifacts to inform your guess. &amp;nbsp;Good luck!&lt;br /&gt;&lt;br /&gt;2. "Sentinel values" - Sentinel values are when you return a non-null value of the correct type, but with a wacky value to signify, well, null!  For example, a binary search that returns -1 if the element isn't found.  This is not the same as returning a default value, which is awesome when appropriate.  Not realizing you're working with a sentinel value is identical to not realizing you are working with null.  When you accidentally use it as a real value, it's gonna be ugly.&lt;br /&gt;&lt;br /&gt;3. Annotations - JSR 305 defines some annotations which allow you to mark up your fields, variables and parameters as @Nonnull, @Nullable, @CheckForNull, @ParametersAreNonNullByDefault, and @ParametersAreNullableByDefault.  A tool like windbags can process these annotations and give you warnings when you break the specification.  I tried this approach for several months, and definitely had some success with it.  However, it has a fair share of false negatives and false positives, and can be noisy.  I gave up on it when I encountered code like this (paraphrased):&lt;br /&gt;@Nonnull Person manager = ...&lt;br /&gt;....&lt;br /&gt;checkNonNull(manager);&lt;br /&gt;manager.getCompany();  //findbugs warns here - it doesn't know the semantics of checkNonNull&lt;br /&gt;&lt;br /&gt;4. Naming conventions - I've tried preceding method names that can return null with a "try", ie tryGetPreferredTheme, and naming fields and vars using "optional", ie&lt;br /&gt;private Theme optionalTheme.&lt;br /&gt;This visually sets of the null access, and worked better than I'd thought.  However, it seems a little noisy, and is very easy to overlook.&lt;br /&gt;&lt;br /&gt;5. The "&lt;a href="http://stackoverflow.com/questions/318657/null-object-design-pattern-question"&gt;Null Object&lt;/a&gt;" Pattern - implement your interface using a "null" implementation. &amp;nbsp;Exactly like returning null, but more confusing.&lt;br /&gt;&lt;br /&gt;Scala/Haskell and many other languages offer a 6th option: the Option type.  In Java, our "getPreferredTheme" would change to this if it used Option:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=wxutJdc7" style="border: none; height: 60px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;Option is an interface with two implementations: "Some" to represent a real value and "None" to represent a null value. &amp;nbsp;Here's the code, adapted from this &lt;a href="http://www.codecommit.com/blog/scala/the-option-pattern"&gt;great article&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=mhsaz0Vb" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;With the change above this would no longer compile:&lt;br /&gt;&lt;br /&gt;person.getPreferredTheme().getBackgoundColor();&lt;br /&gt;&lt;br /&gt;Instead, the two choices are:&lt;br /&gt;1. You just know it won't be null in this one special case:&lt;br /&gt;&lt;br /&gt;person.getPreferredTheme()&lt;b&gt;.get()&lt;/b&gt;.getBackgoundColor().getName();&lt;br /&gt;&lt;br /&gt;get() will get you the actual Theme value if set, or throw a NullPointerException if not.  What, a NPE?  I thought we were avoiding those?  We can't.  I'm striving only to get rid of "bad" NPEs, ones which the programmer access the null reference out of ignorance or neglect.  We only used get() here because we have assured ourselves it should be an error condition if it wasn't set - a "Good" NPE. &amp;nbsp;Think of it as a shortcut for "check for null and error out if it is null".&lt;br /&gt;&lt;br /&gt;2. You're glad you were reminded it was potentially null, and can move on without it.&lt;br /&gt;&lt;br /&gt;if (person.getPreferredTheme().isDefined()) {&lt;br /&gt;...process the data&lt;br /&gt;&lt;br /&gt;Yep, just a standard null check with a fancy name.&lt;br /&gt;&lt;br /&gt;The important thing to note here is that accessing optional data without considering that fact is disallowed by the compiler. This cannot be said of the four approaches described at the beginning of the post. &amp;nbsp;You are moving what was previously developer busywork (which we're notoriously bad at) into the domain of the compiler, which excels at busywork.  And not some whiz-bang language feature like Nullable Types or annotations either - it takes advantage of very simple classes.  &lt;br /&gt;&lt;br /&gt;It's also important to note Option should be used only on types that are specified to be optional. &amp;nbsp;I think a lot of people think Option is intended to protect you from &lt;b&gt;all&lt;/b&gt; NPEs by forcing that extra check each time. Not so - just use it on your truly optional variables, and use your normal variables with confidence.&lt;br /&gt;&lt;br /&gt;Option is absolutely worth trying in your Java project - I intend to try soon. I fear it may require too much boilerplate in Java. &amp;nbsp;Scala (and Haskell and others) make Option more appealing due to much stronger type inference (less noise) and a host of other tools for processing them beyond get() and isDefined().  The other tools available in Scala require much more of a leap of faith/new way of thinking. &amp;nbsp;They're also the source of most of Cedric's skepticism, I believe. &amp;nbsp;I hope to cover them in the next post.&lt;br /&gt;&lt;br /&gt;"If it's worth telling another developer, it's worth telling the compiler"&lt;br /&gt;-Guy Steele&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-7627669349044723774?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/7627669349044723774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=7627669349044723774' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7627669349044723774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7627669349044723774'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/10/scalas-option-will-save-you-from-most.html' title='Scala&apos;s Option will save you from the most common cause of NullPointerException'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-7345798484384893944</id><published>2010-07-09T18:56:00.000-07:00</published><updated>2010-07-09T18:56:37.645-07:00</updated><title type='text'>A new syntax for Java closures/lambdas</title><content type='html'>I'm surprised this isn't making more news. &amp;nbsp;Brian Goetz of Oracle has posted a &lt;a href="http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-2.html"&gt;dramatic revision of Java 7's Project Lambda&lt;/a&gt;. &amp;nbsp;&amp;nbsp;The syntax is much less noisy than the original version, thanks to a lot more type inference for parameters and return types. &amp;nbsp;I'm also really happy with how accessible the document is - the document is very readable, even for a "blue-collar" Java developer like me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-7345798484384893944?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/7345798484384893944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=7345798484384893944' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7345798484384893944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7345798484384893944'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/07/new-syntax-for-java-closureslambdas.html' title='A new syntax for Java closures/lambdas'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-1091300093551823410</id><published>2010-05-27T12:16:00.000-07:00</published><updated>2010-05-27T12:16:39.184-07:00</updated><title type='text'>Oracle pushes first version of Lambda/Closures implementation</title><content type='html'>Test cases may not be the best source of coding gems, as they're probably testing the weirder stuff. &amp;nbsp;But you can now see some test cases, and therefore the evolving syntax &lt;a href="http://hg.openjdk.java.net/lambda/lambda/langtools/file/7704dcd17e0b/test/tools/javac/lambda/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Oracle has a tough task in adding closures to a language that has checked exceptions, minimal type inference, and without breaking compatibility of zillions of lines of existing code. &amp;nbsp;Go Snoracle!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-1091300093551823410?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/1091300093551823410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=1091300093551823410' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1091300093551823410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1091300093551823410'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/05/oracle-pushes-first-version-of.html' title='Oracle pushes first version of Lambda/Closures implementation'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-3838311056337295010</id><published>2010-05-17T10:40:00.000-07:00</published><updated>2010-05-25T07:45:15.999-07:00</updated><title type='text'>Some JUnit tricks for easier and better test cases</title><content type='html'>Whenever I start a new project, the first thing I'll write is a &lt;a href="http://squirrelsewer.blogspot.com/2010/03/filter-your-stack-traces.html"&gt;stack trace filterer/clarifier&lt;/a&gt;. &amp;nbsp;The second would be several enhancements to JUnit. &amp;nbsp;For test driven development to be effective, you need good coverage and lots of tests. &amp;nbsp;For that to happen, tests need to be dead-simple to write, easy to maintain, and fast. &amp;nbsp;The following enhancements have really helped me towards these goals.&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;Easy Fixtures&lt;/b&gt; - Many bugs/regressions will involve a set of complicated data relationships. &amp;nbsp;Create an XML/JSON/whatever format to easily import large sets of data. &amp;nbsp;For example, let's say bug #535 comes in: "Exception is thrown when trying to delete users when they are in a group". &amp;nbsp;You can quickly go out, and create 535.xml:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=8pYDNwfA" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;Then, your test case could be:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=aMSCUEEE" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;Without an extremely easy way to create test fixtures and import them, 99% of us will write far less tests.&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;Automatic transaction handling and application bootstrapping&lt;/b&gt;. &amp;nbsp;Ideally, the example test method I gave above should be all it takes to run the test. &amp;nbsp;No explicit setUp, tearDown for bootstrapping your environment, setting up transactions, etc. &amp;nbsp;It is worth investing your time in some means (maybe a AbstractTest superclass?) &amp;nbsp;to set these things up automatically for the 95% of test cases that require no special environmental setup. &amp;nbsp;Don't Repeat Yourself.&lt;br /&gt;&lt;br /&gt;3. &lt;b&gt;More powerful&amp;nbsp;Set and List comparison&lt;/b&gt; - When I do assertEquals(expected, actual) where "expected" and "actual" are Collections with dozens of elements, the last thing I want to hear that they are not equal, maybe with a toString of both. &amp;nbsp;So I always implement a assertSetsEqual and assertListsEqual. &amp;nbsp;assertSetsEqual compare the two collections, where order doesn't matter. &amp;nbsp; Here's a sample of assertSetsEquals:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=NLA4PcyN" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;The List comparison, where order matters, requires more work to produce a nice message, but it's worth it:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Expected: [a, b, c, d, e, f, g, h, i, j, k]&lt;br /&gt;Actual: &amp;nbsp; [a, b, c, e, f, g, h, i, j, k, l]&lt;br /&gt;Missing 'd' @ 3&lt;br /&gt;Unexpected l @ 10&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Type-checking assertEquals - &lt;/b&gt;Due to limitations of Java's type system, assertEquals takes two parameters of type Object. &amp;nbsp;There can be no compile-time checking that the two arguments are actually of types that can actually have equal objects. &amp;nbsp;For example:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=1wpizbXd" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;I discovered org.junit.Assert as I wrote this, much better than the junit.framework. &amp;nbsp;Why is there two? &amp;nbsp;Just printing the types goes a long way. &amp;nbsp;I'm surprised how often an assertEquals LOOKS right, but it happily returns false because you are passing incompatible types in.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5. An Eclipse template for creating a new test case&lt;/b&gt;. &lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=QFZq8iAg" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;Just laziness mostly, but I do think it's important to have that fail("No Asserts") in there from the start. &amp;nbsp;Too often I'll write a test case as I'm exploring a problem, but then I get distracted and abandon it before I really nail down the asserts. &amp;nbsp;Without asserts, your test case is mostly just slowing things down.&lt;br /&gt;&lt;br /&gt;These little changes seem like overkill in the context of writing a silly little test case. &amp;nbsp;But if your goal is to write hundreds, I found these tricks to be really worth the investment.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update #1: &lt;/b&gt;In the comments, Crias points out that junit.framework is for backwards compatibity with JUnit 3 and earlier and should be avoided if possible. &amp;nbsp;I think a custom assertEquals which uses reflection determine if the two arguments even &lt;i&gt;can&lt;/i&gt;&amp;nbsp;be equal is worthwhile, &amp;nbsp;but the new org.junit goes a long way just by printing class names.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update #2: &lt;/b&gt;In the comments, David Karr correctly points out the the test runner will print any exception that bubbles out a test method created with my template. &amp;nbsp;The reason I took this weird approach is the the Eclipse JUnit runner does not output the trace to the console but to the JUnit View, which I find is a goofy place to inspect the exception. &amp;nbsp;More importantly, the Eclipse runner won't &lt;a href="http://squirrelsewer.blogspot.com/2010/03/filter-your-stack-traces.html"&gt;filter my stack traces&lt;/a&gt;, which I'm addicted to.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update #3: &lt;/b&gt;Tym The Enchanter points out that Hamcrest helps with my #3 and #4 points about better asserts. &amp;nbsp;I know very little about Hamcrest, but here's my naive reaction: &lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;is/equalTo for safer equal to comparisons. &amp;nbsp;These basically force the type of the "actual" to be a subclass (or the same class) as the "expected". &amp;nbsp;This goes a long way to reducing dumb-dumb comparisons like new Integer(2) and "2". &amp;nbsp;In my experience, these are exactly the kinds of comparison errors that slow you down. &amp;nbsp;It's not perfect, however - it's quite possible that the compile time type of your expected is not a subclass of the actual, but they ARE assignable - see the "Garfield" example below. &amp;nbsp;Of course you can fall back to more traditional assertEquals if it bites you, and I'm unsure how often I'd see this in real life. &amp;nbsp;&lt;/li&gt;&lt;li&gt;Set/List comparisons - For sure, Hamcrest beats JUnit asserts here. &amp;nbsp;However, these comparisons basically fail fast - they only tell you the first problem they find - which could lead you to running the test several times before you get it right. &amp;nbsp;Tell me all of the problems right off the bat!&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=WuausFuk" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;Thanks for the comments!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-3838311056337295010?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/3838311056337295010/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=3838311056337295010' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/3838311056337295010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/3838311056337295010'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/05/some-junit-tricks-for-easier-and-better.html' title='Some JUnit tricks for easier and better test cases'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-4945487655371785372</id><published>2010-04-20T10:29:00.000-07:00</published><updated>2010-04-20T10:29:26.679-07:00</updated><title type='text'>Another reason Virtual Machines are amazing</title><content type='html'>&lt;a href="http://github.com/codahale/yoink"&gt;http://github.com/codahale/yoink&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The details aren't important, but basically:&lt;br /&gt;1. Clojure is a Lisp-like language which runs on the JVM, Scala a more C/Java style language which also runs on the JVM.&lt;br /&gt;2. Clojure writes high performance immutable data structures which can handle small updates w/o copying the entire structure.&lt;br /&gt;3. Clever Scala programmer just wraps the Clojure collection in a thin Scala wrapper.&lt;br /&gt;&lt;br /&gt;I know language interop on the JVM has been evolving for some time, but it's especially neat to see when neither of the languages are Java! &amp;nbsp;We're entering an era where you will not know or care what language your libraries are written in.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-4945487655371785372?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/4945487655371785372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=4945487655371785372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4945487655371785372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4945487655371785372'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/04/another-reason-virtual-machines-are.html' title='Another reason Virtual Machines are amazing'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-905033106006838724</id><published>2010-03-25T09:29:00.000-07:00</published><updated>2010-03-30T06:41:59.546-07:00</updated><title type='text'>Filter your stack traces</title><content type='html'>Probably the first utility I write when starting up a new project is ExceptionUtils.getFilteredStackTrace(Throwable e)&lt;br /&gt;The idea here is to:&lt;br /&gt;1. "Flatten" the trace. e.printStackTrace attempts to display the stack trace of the creation of each Exception in the chain.  In my experience, only the stack of the "bottom" exception is interesting.&lt;br /&gt;2. Filter out third party lines.  99% of the time, the offending code is mine, not my library's.  So why show those endless lines from Tomcat, JUnit, Hibernate, etc?  &lt;br /&gt;&lt;br /&gt;Filtering isn't always appropriate.  Sometimes the trace provides good insight into what your libraries are trying to do when the messages aren't clear.  I also recommend turning filtering off in production, where you really need all of the info you can get.  However, most of the time, you mainly just want to see what your own code was up to when the exception was thrown, and this approach removes massive amounts of noise.&lt;br /&gt;&lt;br /&gt;Here's an example.  I took the standard Hibernate Person model and hooked it up to the H2 database.  I altered the model to make username unique, so that this test fails:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=5EB0cPJu" style="border:none;width:100%"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Here's the output from the filtered run:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;HibExample.test: Exception: org.hibernate.exception.ConstraintViolationException: could not insert: [hib.Person]&lt;br /&gt;Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "CONSTRAINT_INDEX_8 ON PUBLIC.PERSON(FIRSTNAME)"; SQL statement:&lt;br /&gt;insert into PERSON (PERSON_ID, age, firstname, lastname) values (null, ?, ?, ?) [23001-132]&lt;br /&gt; 37 lines skipped for [org.h2, org.hibernate, sun., java.lang.reflect.Method, $Proxy]&lt;br /&gt; at hib.HibExample.test(HibExample.java:18)&lt;br /&gt; 24 lines skipped for [sun., java.lang.reflect.Method, org.junit, org.eclipse]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And here's e.printStackTrace&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;org.hibernate.exception.ConstraintViolationException: could not insert: [hib.Person]&lt;br /&gt; at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)&lt;br /&gt; at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)&lt;br /&gt; at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)&lt;br /&gt; at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2176)&lt;br /&gt; at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2656)&lt;br /&gt; at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)&lt;br /&gt; at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)&lt;br /&gt; at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)&lt;br /&gt; at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)&lt;br /&gt; at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)&lt;br /&gt; at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)&lt;br /&gt; at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)&lt;br /&gt; at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)&lt;br /&gt; at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:646)&lt;br /&gt; at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:620)&lt;br /&gt; at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:624)&lt;br /&gt; at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)&lt;br /&gt; at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)&lt;br /&gt; at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)&lt;br /&gt; at java.lang.reflect.Method.invoke(Method.java:597)&lt;br /&gt; at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:342)&lt;br /&gt; at $Proxy4.persist(Unknown Source)&lt;br /&gt; at hib.HibExample.test(HibExample.java:16)&lt;br /&gt; at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)&lt;br /&gt; at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)&lt;br /&gt; at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)&lt;br /&gt; at java.lang.reflect.Method.invoke(Method.java:597)&lt;br /&gt; at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)&lt;br /&gt; at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)&lt;br /&gt; at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)&lt;br /&gt; at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)&lt;br /&gt; at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)&lt;br /&gt; at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)&lt;br /&gt; at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)&lt;br /&gt; at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:44)&lt;br /&gt; at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)&lt;br /&gt; at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)&lt;br /&gt; at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)&lt;br /&gt; at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)&lt;br /&gt; at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)&lt;br /&gt; at org.junit.runners.ParentRunner.run(ParentRunner.java:220)&lt;br /&gt; at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)&lt;br /&gt; at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)&lt;br /&gt; at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)&lt;br /&gt; at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)&lt;br /&gt; at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)&lt;br /&gt; at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)&lt;br /&gt;Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "CONSTRAINT_INDEX_8 ON PUBLIC.PERSON(FIRSTNAME)"; SQL statement:&lt;br /&gt;insert into PERSON (PERSON_ID, age, firstname, lastname) values (null, ?, ?, ?) [23001-132]&lt;br /&gt; at org.h2.message.DbException.getJdbcSQLException(DbException.java:316)&lt;br /&gt; at org.h2.message.DbException.get(DbException.java:167)&lt;br /&gt; at org.h2.message.DbException.get(DbException.java:144)&lt;br /&gt; at org.h2.index.BaseIndex.getDuplicateKeyException(BaseIndex.java:157)&lt;br /&gt; at org.h2.index.PageBtree.find(PageBtree.java:115)&lt;br /&gt; at org.h2.index.PageBtreeLeaf.addRow(PageBtreeLeaf.java:137)&lt;br /&gt; at org.h2.index.PageBtreeLeaf.addRowTry(PageBtreeLeaf.java:92)&lt;br /&gt; at org.h2.index.PageBtreeIndex.addRow(PageBtreeIndex.java:88)&lt;br /&gt; at org.h2.index.PageBtreeIndex.add(PageBtreeIndex.java:79)&lt;br /&gt; at org.h2.table.RegularTable.addRow(RegularTable.java:112)&lt;br /&gt; at org.h2.command.dml.Insert.insertRows(Insert.java:120)&lt;br /&gt; at org.h2.command.dml.Insert.update(Insert.java:82)&lt;br /&gt; at org.h2.command.CommandContainer.update(CommandContainer.java:70)&lt;br /&gt; at org.h2.command.Command.executeUpdate(Command.java:198)&lt;br /&gt; at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:141)&lt;br /&gt; at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:127)&lt;br /&gt; at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)&lt;br /&gt; at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)&lt;br /&gt; ... 44 more&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p/&gt;&lt;b&gt;Update:&lt;/b&gt; &lt;a href="http://pastebin.com/p8aCSeuu"&gt;Here's a good starter version of the filtering code.&lt;/a&gt;  It may have bugs: I quickly ported it.  It depends on Google Collections, because I can no longer imagine coding without them!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-905033106006838724?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/905033106006838724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=905033106006838724' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/905033106006838724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/905033106006838724'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/03/filter-your-stack-traces.html' title='Filter your stack traces'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-2863645047277515713</id><published>2010-03-05T09:44:00.000-08:00</published><updated>2010-03-05T09:44:02.839-08:00</updated><title type='text'>File upload using Jersey Client</title><content type='html'>This post is nothing special - I just wanted to do an http file upload using Jersey's client API.  There's a lot of "noise"/outdated code out there on this topic, just wanted to show an example that worked for me:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=jBUs0ErT" style="border:none;width:100%"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;This requires Jersey 1.1.5 and the optional &lt;a href="https://jersey.dev.java.net/nonav/documentation/latest/user-guide.html#d4e1230"&gt;jersey-multipart module&lt;/a&gt; (the two jars at the bottom of this section)&lt;br /&gt;&lt;br /&gt;If you're just curious about Jersey, look at how simple the server side is for file upload using Jersey:&lt;br /&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=KpDYecMH" style="border:none;width:100%"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Beautiful!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-2863645047277515713?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/2863645047277515713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=2863645047277515713' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2863645047277515713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2863645047277515713'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/03/file-upload-using-jersey-client.html' title='File upload using Jersey Client'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-2693707884921946904</id><published>2010-03-05T04:58:00.000-08:00</published><updated>2010-03-05T04:58:52.536-08:00</updated><title type='text'>Embed code in Blogger/Blogspot posts</title><content type='html'>Many source code snippet sites allow you to easily embed source code in your posts by providing a simple &amp;lt;script&amp;gt; tag for each snippet.  Blogger seems to disable these tags, and I was surprised how little info I could find on the topic.  Luckily, &lt;a href="http://pastebin.com"&gt;Pastebin&lt;/a&gt; provides &amp;lt;iframe&amp;gt;, which works like a charm on Blogger!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-2693707884921946904?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/2693707884921946904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=2693707884921946904' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2693707884921946904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2693707884921946904'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/03/embed-code-in-bloggerblogspot-posts.html' title='Embed code in Blogger/Blogspot posts'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-1893077256005461425</id><published>2010-03-03T20:38:00.000-08:00</published><updated>2010-03-05T04:34:43.630-08:00</updated><title type='text'>Scala features for Java Programmers: Case Classes</title><content type='html'>I'm a Java programmer who's been casually evaluating Scala for about 6 months. &amp;nbsp;I find it very hard to objectively compare the two languages. &amp;nbsp;Would concise collection literals save me significant time every day? &amp;nbsp;Do boilerplate getter methods really ever cause bugs, or do they just offend my sense of style? In what ways can Java be improved to allow me to write better code? What Java-related factors cause me to waste the most time, day-to-day?&lt;br /&gt;&lt;br /&gt;I think that's a very difficult question to answer. &amp;nbsp;So far, I've come up with three principles to help me evaluate various differences between languages:&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1. Would it make my code easier to read?&lt;/div&gt;&lt;div&gt;2. Would I be able to more easily write correct code?&lt;br /&gt;3. Does it addresses common problems I've encountered that are related to Java?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For my first comparison, can you quickly tell me what the bug is here:&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px; line-height: 24px;"&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=DiJhBuDM" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;Did you catch the bug? &amp;nbsp;The problem is I had Eclipse generate hashCode/equals before I added the "_firstName" field. &amp;nbsp;This mistake is very easy to make, and can be brutal to track down in a bigger system. &amp;nbsp;Here's an example of how things break when you screw up hashCode:&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; font-size: 13px; line-height: 24px;"&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=0X5A8Ubu" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; font-size: 13px; line-height: 24px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; line-height: 24px;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: Times; line-height: normal;"&gt;I feel this is an example of where another language may make it easier to write this code correctly. &amp;nbsp;At 96 lines to essentially represent a struct of 5 fields, I'd say another language has ample opportunity to help me make this code more readable. &amp;nbsp;These type of "Bean" objects - heavy on data, light on code, are so common in Java, language level support seems justifiable.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; font-size: 13px; line-height: 24px;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: Times; font-size: medium; line-height: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;One of my favorite Scala features addresses the readability and correctness problems mentioned above: Case Classes. &amp;nbsp;Case Classes build on Scala's already succinct class definition format, and adds some extra goodies such as compiler-generated equals and hashCode methods. &amp;nbsp;Of course, compiler-generated means that as you add/subtract fields, hashCode and equals automatically adjust&amp;nbsp;accordingly.&lt;br /&gt;&lt;br /&gt;I know it seems small, having the compiler maintain hashCode and equals methods on "Bean"-style classes. &amp;nbsp;However, it contributes much to both the readability and correctness of these common classes. &amp;nbsp;Here's the full definition of Person and the test main method in Scala:&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; font-size: 13px; line-height: 24px;"&gt;&lt;iframe src="http://pastebin.com/embed_iframe.php?i=tC8VDnjZ" style="border: none; width: 100%;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #181818; font-family: 'trebuchet MS', 'Lucida Sans Unicode', 'Lucida Sans', sans-serif; font-size: 13px; line-height: 24px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;That one little line at the top gives you: enforced immutable access to all 5 fields, correct hashCode and equals, and even a decent toString! &amp;nbsp;This is 1/96th of the code, and with less bugs. &amp;nbsp;And I'm holding back some additional tricks that Case Classes have.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Of course, Case Classes are not always appropriate. &amp;nbsp;I've often written hashCodes that did not consider certain fields, etc. &amp;nbsp;However, many, many classes I've written in Java would have greatly benefitted from a Case Class-type functionality.&lt;br /&gt;&lt;br /&gt;I certainly don't spend my days debugging hashCode methods, but Case Classes absolutely address all 3 of my principles for evaluating language differences.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-1893077256005461425?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/1893077256005461425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=1893077256005461425' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1893077256005461425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1893077256005461425'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/03/scala-goodies-for-java-programmers.html' title='Scala features for Java Programmers: Case Classes'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-7811502888393307363</id><published>2010-01-22T08:44:00.000-08:00</published><updated>2010-01-22T08:45:56.641-08:00</updated><title type='text'>Nice online JSON formatter</title><content type='html'>&lt;a href="http://www.bodurov.com/JsonFormatter/"&gt;http://www.bodurov.com/JsonFormatter/&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Formats to nice collapsible/expandable format, processed completely client side.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-7811502888393307363?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/7811502888393307363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=7811502888393307363' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7811502888393307363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7811502888393307363'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/01/nice-online-json-formatter.html' title='Nice online JSON formatter'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-7018012925947050599</id><published>2010-01-12T05:32:00.000-08:00</published><updated>2010-05-17T11:21:29.111-07:00</updated><title type='text'>4 Great Resources For Getting Started With Scala</title><content type='html'>I've been aware of Scala for years, and it never really caught my interest.  Every time I'd seen a Scala example, it was an insanely dense block of code solving some problem I'd never had before.  However, once &lt;a href="http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html"&gt;the creator of Groovy essentially endorsed Scala&lt;/a&gt;, I decided it was worth a closer look.  I've since looked at a LOT of Scala content and these 4 resources really stand out for me.  If you're interested in Scala, I highly recommend you start here: &lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Programming-Scala-Comprehensive-Step-step/dp/0981531601/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1263303201&amp;amp;sr=8-1"&gt;Programming In Scala&lt;/a&gt; - This is simply a great general-purpose programming book.  In addition to being a gentle, clear introduction to the language, it's also a fantastic introduction to functional programming concepts and language design.  Even if you hate Scala, this book will make you a better programmer.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.infoq.com/presentations/Scala-Jonas-Boner"&gt;Pragmatic Real-World Scala&lt;/a&gt; - This video shows off all kinds of things that would make a Java developer drool.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.codecommit.com/blog/scala/roundup-scala-for-java-refugees"&gt;Scala For Java Refugees&lt;/a&gt; - Very well-written mostly gentle introduction to major Scala concepts.&lt;/li&gt;&lt;li&gt;&lt;a href="http://daily-scala.blogspot.com/"&gt;Daily Scala&lt;/a&gt; - Once you've done 1-3, and have written a few Scala apps, subscribe to Daily Scala.  Thoughtful, bite-sized examples nearly every day.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.naildrivin5.com/scalatour"&gt;Another tour of Scala&lt;/a&gt;&amp;nbsp;- A Java-centric breakdown of fundamental Scala features.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-7018012925947050599?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/7018012925947050599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=7018012925947050599' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7018012925947050599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7018012925947050599'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2010/01/4-great-resources-for-getting-started.html' title='4 Great Resources For Getting Started With Scala'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-2236145459229221368</id><published>2008-07-17T11:58:00.001-07:00</published><updated>2008-07-17T12:06:42.839-07:00</updated><title type='text'>Keep terminated launch consoles in Eclipse</title><content type='html'>This one bugs me every time I upgrade to a new release of Eclipse.  I often like to look back at the consoles from main methods/junits/tomcat launches I've terminated.  I guess I expect to find a preference right in the context menu preferences for the Console view, or for it to match "terminated" in the prefs search - no luck.&lt;br /&gt;&lt;br /&gt;So that I never have to search for this again, this preference can be found under&lt;br /&gt;Run/Debug =&gt; Launching =&gt; "Remove terminated launches when a new launch is created"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-2236145459229221368?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/2236145459229221368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=2236145459229221368' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2236145459229221368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2236145459229221368'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/07/keep-terminated-launch-consoles-in.html' title='Keep terminated launch consoles in Eclipse'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-4386077247158654168</id><published>2008-07-16T12:59:00.000-07:00</published><updated>2008-07-16T13:19:53.708-07:00</updated><title type='text'>Wednesday Afternoon Reflections</title><content type='html'>What does this print?&lt;br /&gt;&lt;br /&gt;import java.lang.reflect.Method;&lt;br /&gt;&lt;br /&gt;interface IMessage {&lt;br /&gt;    public CharSequence getMessage();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class SayWhat implements IMessage {&lt;br /&gt;    public String getMessage() {&lt;br /&gt;        return "Hi!";&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] _args) {&lt;br /&gt;        try {&lt;br /&gt;            SayWhat instance = new SayWhat();&lt;br /&gt;            for (Method m : SayWhat.class.getMethods()) {&lt;br /&gt;                if (m.getName().equals("getMessage")) {&lt;br /&gt;                    System.out.println("SayWhat.main: " + m.invoke(instance));&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        catch (Throwable e) {&lt;br /&gt;            System.out.println("SayWhat.main: " + e);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;The answer is&lt;br /&gt;Hi!&lt;br /&gt;Hi!&lt;br /&gt;&lt;br /&gt;That's right, the getMessage method appears twice in SayWhat.class.getMethods().  The key here is that the SayWhat class is overriding IMessage with a covariant return type (CharSequence vs. String).  Looks like the compiler makes covariant return types possible by creating a behind-the-scenes "synthetic" implementation of getMessage which just calls through to my implementation.&lt;br /&gt;&lt;br /&gt;If you find yourself looping through a list of Method objects looking for a match, be sure to check isSynthetic on each Method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-4386077247158654168?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/4386077247158654168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=4386077247158654168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4386077247158654168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4386077247158654168'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/07/wednesday-afternoon-reflections.html' title='Wednesday Afternoon Reflections'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-6079092901642808472</id><published>2008-03-24T14:11:00.001-07:00</published><updated>2010-01-24T05:06:53.993-08:00</updated><title type='text'>Download sources for javax libraries</title><content type='html'>If you are lucky like me, you often find yourself wanting to see the source code for various javax libraries (JavaMail, JSTL, EL, etc).   My success in tracking down the complete zips of these sources varied from project to project.  Today, I stumbled across this:&lt;br /&gt;&lt;a href="http://download.java.net/maven/1/"&gt;http://download.java.net/maven/1/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This looks like a good starting place if you are after javax sources or jars.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-6079092901642808472?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/6079092901642808472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=6079092901642808472' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/6079092901642808472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/6079092901642808472'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/03/download-sources-for-javax-libraries.html' title='Download sources for javax libraries'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-6005149109749248167</id><published>2008-03-11T07:40:00.000-07:00</published><updated>2008-03-11T08:33:56.194-07:00</updated><title type='text'>ical4j, JavaMail, Exchange and Outlook secret sauce</title><content type='html'>Last summer, I was tasked with sending out Outlook "meeting invites" for events in our product.  This meant integrating with iCal4j.  iCal4j itself has a truly bizarre API, but it wasn't bad to create a new invite, as there are so many examples out there.  What really stumped me for a while was getting the headers right so that Outlook would pop up an "Accept/Decline" dialog for automatically adding the event to their calendar.  I should have blogged about this last summer, as I've now forgotten what I finally did to make it work - I believe the real coup was getting the headers right.  I remember finding lots of people with similar problems, so I wanted to get this code out there.&lt;br /&gt;&lt;br /&gt;This code requires iCal4j and JavaMail 1.4.  I believe the JavaMail 1.4-only ByteArrayDataSource is crucial for getting this to work.  This code might not even work for you, I just wanted to get it out there as a starting point.&lt;br /&gt;&lt;br /&gt;public MimeMessage createMimeMessage(Session _javaMailsession) throws Exception {&lt;br /&gt;        MimeMessage mimeMessage = new MimeMessage(_javaMailsession);&lt;br /&gt;        mimeMessage.setSubject(getSubject());&lt;br /&gt;        mimeMessage.addFrom(getFromInternetAddresses());&lt;br /&gt;        mimeMessage.addRecipients(Message.RecipientType.TO, getFromInternetAddresses());&lt;br /&gt;        Multipart multipart = new MimeMultipart();&lt;br /&gt;        MimeBodyPart iCalAttachment = new MimeBodyPart();&lt;br /&gt;        byte[] invite = createICalInvitation(getMeetingID(), getSubject(), getContent(), getMeetingStart(), getMeetingEnd(), getMeetingTimeZone());&lt;br /&gt;        iCalAttachment.setDataHandler(new DataHandler(new ByteArrayDataSource(new ByteArrayInputStream(invite), "text/calendar;method=REQUEST;charset=\"UTF-8\"")));&lt;br /&gt;        multipart.addBodyPart(iCalAttachment);&lt;br /&gt;        mimeMessage.setContent(multipart);&lt;br /&gt;        return mimeMessage;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private byte[] createICalInvitation(String _meetingID, String _subject, String _content, Date _start, Date _end, TimeZone _tz) throws Exception {&lt;br /&gt;        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_OUTLOOK_COMPATIBILITY, true);&lt;br /&gt;&lt;br /&gt;        VEvent vEvent = new VEvent();&lt;br /&gt;        vEvent.getProperties().add(new Uid(_meetingID));&lt;br /&gt;        vEvent.getProperties().add(new Summary(_subject));&lt;br /&gt;        vEvent.getProperties().add(new Description(_content));&lt;br /&gt;        vEvent.getProperties().add(new DtStart(new DateTime(_start)));&lt;br /&gt;        vEvent.getProperties().add(new DtEnd(new DateTime(_end)));&lt;br /&gt;&lt;br /&gt;        net.fortuna.ical4j.model.Calendar cal = new net.fortuna.ical4j.model.Calendar();&lt;br /&gt;        cal.getProperties().add(new ProdId("-//iloveoutlook//iCal4j 1.0//EN"));&lt;br /&gt;        cal.getProperties().add(net.fortuna.ical4j.model.property.Version.VERSION_2_0);&lt;br /&gt;        cal.getProperties().add(CalScale.GREGORIAN);&lt;br /&gt;        cal.getProperties().add(net.fortuna.ical4j.model.property.Method.REQUEST);&lt;br /&gt;        TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();&lt;br /&gt;        VTimeZone tz = registry.getTimeZone(_tz.getID()).getVTimeZone();&lt;br /&gt;        cal.getComponents().add(tz);&lt;br /&gt;        cal.getComponents().add(vEvent);&lt;br /&gt;&lt;br /&gt;        ByteArrayOutputStream bout = new ByteArrayOutputStream();&lt;br /&gt;        CalendarOutputter outputter = new CalendarOutputter();&lt;br /&gt;        outputter.output(cal, bout);&lt;br /&gt;        return bout.toByteArray();&lt;br /&gt;    }&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-6005149109749248167?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/6005149109749248167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=6005149109749248167' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/6005149109749248167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/6005149109749248167'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/03/ical4j-javamail-exchange-and-outlook.html' title='ical4j, JavaMail, Exchange and Outlook secret sauce'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-4494844816880302873</id><published>2008-02-22T08:59:00.000-08:00</published><updated>2008-02-22T09:05:23.527-08:00</updated><title type='text'>Firefox 3</title><content type='html'>I've been playing around with beta 3 of Firefox.  It's definitely stable enough to use all day, I can't say I've had any real problems yet.  The speed is dramatically improved.  I'm also enjoying much smarter auto-complete in the address bar.&lt;br /&gt;&lt;br /&gt;One must-have config tweak if you plan on using Google Reader with ff3, via &lt;a href="http://crazybob.org/2007/06/tweets.html"&gt;crazybob&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;To load all new Firefox tabs in the background, set "browser.tabs.loadDivertedInBackground" to "true" in "about:config".&lt;br /&gt;...&lt;br /&gt;My last tweet makes the "v" shortcut in Google Reader imminently more useful.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-4494844816880302873?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/4494844816880302873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=4494844816880302873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4494844816880302873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4494844816880302873'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/02/firefox-3.html' title='Firefox 3'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-1327967973718234012</id><published>2008-02-06T14:02:00.000-08:00</published><updated>2008-02-06T14:14:00.065-08:00</updated><title type='text'>Tuesday auto-boxing nugget</title><content type='html'>What does the following print?&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt; &lt;!--code { font-family: Courier New, Courier; font-size: 10pt; margin: 0px; }--&gt;&lt;&lt;/style&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;public static &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;void &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;main&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;String&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;[] &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;_args&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;System.out.println&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.isAssignableFrom&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Boolean.&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;))&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;System.out.println&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Boolean.&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.isAssignableFrom&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;))&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;System.out.println&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Boolean.&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.isInstance&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;))&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;System.out.println&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;.isInstance&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(127, 0, 85);"&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;))&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;  &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; The answer:&lt;br /&gt;false&lt;br /&gt;false&lt;br /&gt;true&lt;br /&gt;false&lt;br /&gt;&lt;br /&gt;This makes sense when you think about it, but it can definitely trip you up when you've become accustomed to auto-boxing.  Incidentally, this is my first true "gotcha" w/ auto-boxing in the 2.5 years I've been using it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- end source code --&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- =       END of automatically generated HTML code       = --&gt;&lt;br /&gt;&lt;!-- ======================================================== --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-1327967973718234012?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/1327967973718234012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=1327967973718234012' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1327967973718234012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1327967973718234012'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/02/tuesday-auto-boxing-nugget.html' title='Tuesday auto-boxing nugget'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-5571953957745977351</id><published>2008-02-05T18:25:00.000-08:00</published><updated>2008-02-05T18:30:12.612-08:00</updated><title type='text'>Analyzing huge HeapDumpOnOutOfMemoryError heap files</title><content type='html'>I &lt;a href="http://squirrelsewer.blogspot.com/2007/02/excellent-vm-flag.html"&gt;previously mentioned&lt;/a&gt; a JVM flag that has the potential to really clarify things when you encounter a OutOfMemoryError in production.&lt;br /&gt;&lt;br /&gt;When I first utilized this flag, my heap dump file was probably about 500M. It's a year later, and we just had another OutOfMemoryError (OOM). This time, the heap dump size was more like 1.1G. If you've ever struggled with Java OOMs on 32-bit Windows in the past, you know 1.1 is effectively the largest heap size you can get away with. I don't necessarily agree with -Xmx1.1G in the least, but that's a different post.&lt;br /&gt;&lt;br /&gt;It appears that to analyze a 1.1G heap dump file, jhat requires greater than 1.1G of heap allocated for the analysis. In other words, if you max out heap on your application, you won't be able to &lt;span style="font-style: italic;"&gt;analyze&lt;/span&gt; the heap dump on a similar machine.  In other words, if you max out heap on a 32-bit OS, you'll need a 64-bit OS to analyze it.&lt;br /&gt;&lt;br /&gt;I also tried &lt;a href="https://www.sdn.sap.com/irj/sdn/wiki?path=/display/Java/Java+Memory+Analysis"&gt;SAP Memory Analyzer&lt;/a&gt; and YourKit on my 32-bit machine, just to see. Same experience - the OOM analysis tools crash with an OOM. Finally, I tried SAP Memory Analyzer on a 64 bit machine, and it worked well. After seeing the contents of the heap, it was very easy to diagnose the problem. I'm not sure I ever would have solved the problem w/o it.&lt;br /&gt;&lt;br /&gt;I've since found out the &lt;a href="http://www.yourkit.com/eap/index.jsp"&gt;YourKit 7.1 EAP&lt;/a&gt; can handle massive heap dumps on 32 bit machines: I was able to analyze the file by passing in -Xmx700M to YourKit. Overall, I was really impressed w/ SAP and YourKit in terms of polish and responsiveness from support.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-5571953957745977351?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/5571953957745977351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=5571953957745977351' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/5571953957745977351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/5571953957745977351'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2008/02/analyzing-huge-heapdumponoutofmemoryerr.html' title='Analyzing huge HeapDumpOnOutOfMemoryError heap files'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-8213866218151709030</id><published>2007-02-22T06:58:00.000-08:00</published><updated>2007-02-23T09:39:15.409-08:00</updated><title type='text'>Timezone problems, a few weeks early</title><content type='html'>Due to some serious ambiguities (Australia has an EST, China has a CST), Sun deprecated three-digit timezone IDs as of Java 1.4.  Well, they really meant it: as of Java 1.5_08, "EST" shifts from traditional Eastern Standard Time to a 1980s System V timezone name for "Indiana, with DST not observed."  The &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6466476"&gt;bug &lt;/a&gt;and &lt;a href="http://article.gmane.org/gmane.comp.time.tz/1414"&gt;related&lt;/a&gt; &lt;a href="http://article.gmane.org/gmane.comp.time.tz/1415"&gt;thread&lt;/a&gt; are an interesting insight into how TimeZones are managed in the software world.&lt;br /&gt;&lt;br /&gt;For reasons long forgotten, we had some ancient code which allowed us to configure the VM-wide TimeZone, and we defaulted to "EST" - ouch.   Changing that to America/New_York fixed the problem, but I didn't understand how default timezone was affecting our date formatting.  I conceptualized databases storing Timestamps as what Joda would call an "Instant", or others would call "epoch time": what you get when you call System.currentTimeMillis.  Instants don't have timezones, but represent a moment precisely:&lt;br /&gt;&lt;br /&gt;1149138000000 == 6/1/2006 2:00 PM EST == 6/1/2006 11:00 AM PST&lt;br /&gt;&lt;br /&gt;I was assuming the database essentially stores "1149138000000".  When you read that value out, you get a Timestamp back, with this Instant as its backing time.  After all, Timestamp/Date essentially represent Instants: look at their getTime() method.  Once you have a Timestamp, you can easily format it to any timezone using DateFormat and TimeZone objects.  With these horribly flawed ideas, I didn't see where default timezone fit in.&lt;br /&gt;&lt;br /&gt;Boy, was I wrong.  Consider the following SQL:&lt;br /&gt;INSERT INTO DateTest (DateField) VALUES {ts '2006-06-01 00:14:00.00'}&lt;br /&gt;How do you convert that to an Instant?  Of course, you can't - that could be 2 PM in any one of dozens of timezones - all different Instants.  Really, the database is just holding the various month/day/hour/etc values - it's up to the code reading the value to make it into an Instant.  Considering that java.sql.Timestamp really is an Instant, it's pretty weird to reconsider this code:&lt;br /&gt;Timestamp ts = rs.getTimestamp("DateField");&lt;br /&gt;Which 2PM instant will "ts" represent??  JDBC will apply the VM default timezone in this case.  getTimestamp provides a method which will probably make things more clear:&lt;br /&gt;public Timestamp getTimestamp(String columnName, Calendar cal);&lt;br /&gt;I'm still unclear as to why this takes Calendar, and not TimeZone, but I'm done with investigating for a while :)&lt;br /&gt;&lt;br /&gt;Lessons:&lt;br /&gt;1. Don't use three-digit timezone codes for looking up timezones!&lt;br /&gt;2. DATE and TIMESTAMP columns do not store TimeZone info, or even Instant info. &lt;br /&gt;3. Web programmers should be very careful with TimeZone.setDefaultTimeZone, its scope is either VM-wide &lt;span style="font-style: italic;"&gt;or&lt;/span&gt; ThreadLocal, depending on your permissions.&lt;br /&gt;4. Instead of setDefaultTimeZone, consider the Calendar-based permutations of getTimeXXX(....) in ResultSet.  This is much more clear, and will avoid the scoping problems described in #3&lt;br /&gt;5. TimeZone.getTimeZone("someIDThatDoesntExist") .equals(TimeZone.getTimeZone("GMT") )- &lt;span style="font-weight: bold;"&gt;BOO!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-8213866218151709030?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/8213866218151709030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=8213866218151709030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/8213866218151709030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/8213866218151709030'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2007/02/timezone-problems-few-weeks-early.html' title='Timezone problems, a few weeks early'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-1181903338213631471</id><published>2007-02-21T07:43:00.000-08:00</published><updated>2008-02-05T18:25:20.313-08:00</updated><title type='text'>Excellent VM flag</title><content type='html'>This is a bit dated, but if you're using Java 1.5 or 1.4.2, there's an excellent flag in more recent VM updates: HeapDumpOnOutOfMemoryError.  OOMs have to be one of the hardest problems to debug: traditionally, you'll have next to zero information on the cause of the crash.  This flag apparently has no runtime cost, and will provide a thorough snapshot of the heap at the time of the crash.  I hadn't had a "out of heap space"-style OOM in years, but recently had one.  Luckily, this flag was enabled, and I was able to use the "jhat" tool to pretty quickly find the culprit.  I had some problems with the &lt;a href="https://hat.dev.java.net/"&gt;java.net HAT&lt;/a&gt; tool, but the jhat which is distributed with Mustang worked perfectly.  This is one of those simple changes that can really save you later.&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.sun.com/alanb/entry/heapdumponoutofmemoryerror_option_in_5_0u7"&gt;All the info&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-1181903338213631471?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/1181903338213631471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=1181903338213631471' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1181903338213631471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/1181903338213631471'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2007/02/excellent-vm-flag.html' title='Excellent VM flag'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-7007045158389054187</id><published>2007-02-08T06:22:00.000-08:00</published><updated>2007-01-11T12:05:25.401-08:00</updated><title type='text'>When generic type inference fails</title><content type='html'>99% of the time, using generics is perfectly natural and pleasurable.  The other 1%, it can be downright humbling.&lt;br /&gt;&lt;br /&gt;Look at the signature of Arrays.asList:&lt;br /&gt;&lt;br /&gt;public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; asList(T... a)&lt;br /&gt;&lt;br /&gt;Going to take in an array of type T, and return a List containing the same type.  But what is T?  The parameter "a" is just a set of parameters the caller may have just defined in-place - with no explicit declaration of T.  This is only a problem when the varargs passed in are of diverse types:&lt;br /&gt;&lt;br /&gt;Arrays.asList(new Thing&amp;lt;Integer&amp;gt;(), new Thing&amp;lt;String&amp;gt;(), new Thing&amp;lt;String&amp;gt;());&lt;br /&gt;&lt;br /&gt;In this case, the compiler must find the lowest common denominator type.  Unfortunately, with the eclipse compiler at least, that's a tad insane - it would decide the common type is this:&lt;br /&gt;&lt;br /&gt;Thing&amp;lt;? extends Object&amp;Comparable&amp;lt;?&amp;gt;&amp;Serializable&amp;gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;Yuck! It's true, that in a vacuum, there's not much else the compiler can do.  But what about when I give it more info?&lt;br /&gt;&lt;br /&gt;public List&amp;lt;Thing&amp;gt;&amp;gt; getThings() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;return Arrays.asList(new Thing&amp;lt;Integer&amp;gt;(), new Thing&amp;lt;String&amp;gt;(), new Thing&amp;lt;String&amp;gt;());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;The compiler complains that it can't convert its insane type to what would appear to be a proper "super" type: Thing.  It doesn't seem to me the compiler is taking advantage of all the info I'm giving it.  To be fair, I'm sure there are tons of situations where the compiler has no additional context to take advantage of.&lt;br /&gt;&lt;br /&gt;However, there's hope.  In his post &lt;a href="http://blogs.sun.com/ahe/entry/java_se_7_wish_list"&gt;Java 7 Wish List&lt;/a&gt; , the author describes a way (which is in Java 5, btw) to give the compiler more of a nudge:&lt;br /&gt;&lt;br /&gt;Arrays.&amp;lt;Thing&amp;lt;?&amp;gt;&amp;gt;asList(new Thing&amp;lt;Integer&amp;gt;(), new Thing&amp;lt;String&amp;gt;());&lt;br /&gt;&lt;br /&gt;Hey, it aint pretty, but my only guess to the alternative is a bit too verbose:&lt;br /&gt;List&amp;lt;Thing&amp;gt; things = new ArrayList&amp;lt;Thing&amp;gt;();&lt;br /&gt;things.add(new Thing&amp;lt;Integer&amp;gt;());&lt;br /&gt;things.add(new Thing&amp;lt;String&amp;gt;());&lt;br /&gt;&lt;br /&gt;Actually, you CAN cast:&lt;br /&gt;&lt;br /&gt;(List&amp;lt;Thing&amp;lt;?&amp;gt;&amp;gt;)Arrays.asList(new Thing&amp;lt;Integer&amp;gt;(), new Thing&amp;lt;String&amp;gt;(), new Thing&amp;lt;String&amp;gt;());&lt;br /&gt;&lt;br /&gt;But this works only on eclipse, not javac.  Plus, doesn't it feel a little to ironic to &lt;span style="font-style: italic;"&gt;add&lt;/span&gt; a cast to accomodate generics :)&lt;br /&gt;&lt;br /&gt;PS. Dear Google programmers, please use your 15% time to make it a lot easier to add code snippets to blog entries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-7007045158389054187?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/7007045158389054187/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=7007045158389054187' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7007045158389054187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/7007045158389054187'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2007/02/when-generic-type-inference-fails.html' title='When generic type inference fails'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-2318091661642780476</id><published>2007-01-11T11:56:00.000-08:00</published><updated>2007-01-11T12:05:25.160-08:00</updated><title type='text'>Portable SQL?</title><content type='html'>The app I work on is going on 7 years old.  We're slowly migrating to Hibernate, but there's plenty of "old fashioned" JDBC assets left.  So, I maintain DDL for about 80 tables and 40 views.  We've always tried to keep it portable.  So far, the same DDL has run on Oracle, MySQL, Postgres, Derby, and Mckoi.  You can imagine my &lt;span style="font-style: italic;"&gt;shock&lt;/span&gt; when this didn't hold up when I tried SQL Server 2000.  SQL Server has no DATE type, and has a bizarre (and deprecated) TIMESTAMP type which really has nothing do w/ storing traditional timestamps.  They want you to use the "DATETIME" type for both. &lt;br /&gt;&lt;br /&gt;I desperately want to a single set of portable, "pure" DDL for all of these databases, but I may be out of luck.  I was able to fix the lack of DATE type by adding an "alias type":&lt;br /&gt;&lt;br /&gt;            CallableStatement cs = getConnection().prepareCall("{call sp_addtype(?, ?, ?)}");&lt;br /&gt;            cs.setString(1, "DATE");&lt;br /&gt;            cs.setString(2, "DATETIME");&lt;br /&gt;            cs.setString(3, "NOT NULL");&lt;br /&gt;            cs.executeUpdate();&lt;br /&gt;&lt;br /&gt;But I can't do the same for TIMESTAMP, since it's a reserved word.  There must be something clever that can be done...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-2318091661642780476?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/2318091661642780476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=2318091661642780476' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2318091661642780476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/2318091661642780476'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2007/01/portable-sql.html' title='Portable SQL?'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-5047599855405063551</id><published>2007-01-11T11:47:00.000-08:00</published><updated>2007-01-11T11:55:51.518-08:00</updated><title type='text'>Acrobat replacement</title><content type='html'>Over the years, my hate affair with Acrobat Reader has grown. &lt;br /&gt;1. The UI seemed to block until the entire document was downloaded&lt;br /&gt;2. The slow startup time, complimented by their oh-so-impressive patent list&lt;br /&gt;3. The ever present, marketing driven, "Update Reminder"&lt;br /&gt;4. The downright goofy interface.&lt;br /&gt;&lt;br /&gt;It got so bad, I'd skip PDF hits in search results - that's insane.  I was SO happy to stumble across &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.foxitsoftware.com/pdf/rd_intro.php"&gt;Foxit Reader&lt;/a&gt;.  For my purposes at least, it's a fully functional drop-in replacement for Acrobat.   I haven't had a single problem with it, and it's downright snappy.  And it's free.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-5047599855405063551?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/5047599855405063551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=5047599855405063551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/5047599855405063551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/5047599855405063551'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2007/01/acrobat-replacement.html' title='Acrobat replacement'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-4651207793158540716</id><published>2006-11-29T07:37:00.000-08:00</published><updated>2006-11-29T08:03:14.564-08:00</updated><title type='text'>Resource bundle syntax gotchas</title><content type='html'>What's wrong with this property resource bundle entry?&lt;br /&gt;&lt;br /&gt;importantMessage={0}'s account status is now {1}&lt;br /&gt;&lt;br /&gt;For people who are experienced with resource bundles, this is probably obvious: that single ' escapes the rest of the string from &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html"&gt;MessageFormat &lt;/a&gt;processing.  Also, since it's an escape character, it will not be displayed, regardless of MessageFormat.  It's too bad MessageFormat doesn't fail when the ' goes unclosed.  A double ' acts as a replacement for '.  Our team knows this rule, but inevitably some messages get the single tick anyway.  I was pleased to find out that I could mass-fix this using Eclipse's search and replace feature.  I know the search feature supported regexes, but was unaware the replace feature was also regex aware.  The trick is I wanted to replace only single ticks, not ticks part of a double tick.  The regex for finding these:&lt;br /&gt;[^']{1}'[^']{1}&lt;br /&gt;aka "one non tick followed by a tick, followed by one non-tick"&lt;br /&gt;But to do a replace, I needed to preserve the non-tick values on either side of the tick.  Luckily, Eclipse replace understands regex groups.  I changed the match to capture the non-ticks:&lt;br /&gt;([^']{1})'([^']{1})&lt;br /&gt;And replaced matches with&lt;br /&gt;$1''$2&lt;br /&gt;&lt;br /&gt;I thought that was handy.&lt;br /&gt;&lt;br /&gt;On a side note, don't use colons in your key name in a PropertyResourceBundle.&lt;br /&gt;important:Message=Watch out!&lt;br /&gt;Properties parses that as&lt;br /&gt;key = important&lt;br /&gt;value = Message=Watch out!&lt;br /&gt;&lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load%28java.io.InputStream%29"&gt;Properties.load&lt;/a&gt; equates ":" with "=".  Who knew?  Not me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-4651207793158540716?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/4651207793158540716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=4651207793158540716' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4651207793158540716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/4651207793158540716'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2006/11/resource-bundle-syntax-gotchas.html' title='Resource bundle syntax gotchas'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-114918034062576873</id><published>2006-06-01T09:40:00.000-07:00</published><updated>2006-06-01T09:45:40.643-07:00</updated><title type='text'>mailing lists as rss</title><content type='html'>I can't stand mailing lists.  They're just so goofy to subscribe/unsuscribe/track.  I was pleasantly suprised to find most major Java related mailing lists (and lots more) are published by gmane as rss feeds:&lt;br /&gt;&lt;br /&gt;http://blog.gmane.org/index.php?prefix=gmane.comp.java&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-114918034062576873?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/114918034062576873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=114918034062576873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/114918034062576873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/114918034062576873'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2006/06/mailing-lists-as-rss.html' title='mailing lists as rss'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-113477084251147989</id><published>2005-12-16T13:39:00.000-08:00</published><updated>2005-12-16T14:07:22.546-08:00</updated><title type='text'>Inflammatory Ruby Questions</title><content type='html'>I have some honest questions for Ruby experts to help me understand where I am on this Ruby debate.  Not that any Ruby experts, or &lt;span style="font-style: italic;"&gt;anyone&lt;/span&gt; reads this blog, but it makes me feel good, ok? &lt;br /&gt;I honestly want to understand why and how Ruby is going to be a revolution.  I absolutely love Java, but I am deathly afraid I will my love for it will blind me from seeing the next big thing.&lt;br /&gt;&lt;br /&gt;I'd like to seperate Ruby and Ruby on Rails for clarification.&lt;br /&gt;&lt;br /&gt;Ruby:&lt;br /&gt;What is it about this language that seperates it from the dynamically-typed crowd?  Does it hit the sweet spot between loose typing and "true" OO features?  Is it fair to Ruby a great dynamically typed language, and short circuit this half of the discussion as the ancient "staticly versus dynamically typed languages" debate?   My point is I dont see much of a difference between "Ruby v. Java" and "Static v. Dynamic typing" debates.  Is there something novel Ruby adds to that debate?   Perhaps Ruby does for dynamically typed languages what Java did for statically typed languages?&lt;br /&gt;&lt;br /&gt;Ruby On Rails:&lt;br /&gt;What does Ruby on Rails provide that other language web frameworks cannot?  I'm sure "convention over configuration" is a fantastic innovation for small, simple webapps, but what precludes another framework from mimicking this, such as Trails?  I understand Ruby ensusiasts' frustration w/ "XML hell", but that's not a function of Java in the least, but in the frameworks they choose.&lt;br /&gt;&lt;br /&gt;If these were both true statements:&lt;br /&gt;"Ruby is the best dynamically typed language available"&lt;br /&gt;"Ruby on Rails is an innovative web framework for writing simple webapps with very little work"&lt;br /&gt;I see&lt;span style="font-style: italic;"&gt; plenty&lt;/span&gt; of room left for Java.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-113477084251147989?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/113477084251147989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=113477084251147989' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113477084251147989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113477084251147989'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2005/12/inflammatory-ruby-questions.html' title='Inflammatory Ruby Questions'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-113448270977001952</id><published>2005-12-13T05:56:00.000-08:00</published><updated>2005-12-13T06:05:09.783-08:00</updated><title type='text'>Simple logging improvement</title><content type='html'>No matter how clever you are about logging, you will run in to problems in production where you need more information.  Often times, I'll resort to access logs to try to understand more.  I recently made two changes to the default access log format in Tomcat which have drastically increased the utility of these logs.  I added session ID (%S) and "Time taken to process the request" (%D).  If you take care to log session ID in your normal logs, you'll have a nice "foreign key" into the access logs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-113448270977001952?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/113448270977001952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=113448270977001952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113448270977001952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113448270977001952'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2005/12/simple-logging-improvement.html' title='Simple logging improvement'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-113444168067584571</id><published>2005-12-12T17:28:00.000-08:00</published><updated>2005-12-12T18:41:20.720-08:00</updated><title type='text'>Tiger Beat!</title><content type='html'>1. Enhanced for loop is pure coding joy, especially in nested loops, but you will be suprised at how often you can't use it: you need the index, special exit condition (I'm not a "break" man), or you have an iterator. &lt;br /&gt;&lt;br /&gt;2. Generics will improve your API dramatically.  The rap on them is that creating your own generic classes can get messy, and that's true.  But it's not _that_ bad, and 99% of the time you are simply using generic classes, which is completely simple. &lt;br /&gt;&lt;br /&gt;Before generics, we often deliberated about what type to return when a method produced a group of objects (Not a group of "expensive" objects, like objects read from a database - they pretty much necessitate an Iterator).  Arrays were succinct and type-safe.  Collections were what the method often used internally and were more flexible, but lacked type safety.  For us, in a big system, readability won out, and we chose arrays.  Overall, I was happy with the choice, but it didn't sit well how often we'd convert a List to an array at the end of the method.  Generics resolved this completely.  Now all methods return "generified" collections objects, and we get the best of both worlds. &lt;br /&gt;&lt;br /&gt;Map.get/containsKey/remove and Set.contains are NOT generic.  Good discussion:&lt;br /&gt; http://forum.java.sun.com/thread.jspa?threadID=465357&amp;messageID=2139377&lt;br /&gt;&lt;br /&gt;It takes a while to really get used to the fact that generics info is not available at runtime.  Once you understand that, you'll find yourself more a user of generics classes than an author of generics classes.&lt;br /&gt;&lt;br /&gt;3. java.util.concurrent - Great libraries change how you think about problems.  java.util.concurrent is no exception.  Simple concurrency problems are now actually simple to solve.  I'm able to express amazingly powerful concurrent problems in simple and &lt;span style="font-style: italic;"&gt;safe&lt;/span&gt; code.  I don't know how I lived before ConcurrentHashMap, Executor, Callable, and Future.  I now look forward, rather than dread, the next concurrency programming problem.&lt;br /&gt;&lt;br /&gt;4. @Override - Love it.  Even though I haven't programmed Perl in 8 years, I still get a thrill when the compiler points out a problem I never would have noticed.  Errors that @Override solve are pretty rare, but they've saved me once, and that's enough for the "Love it" designation.  While I understand it would be trickier, an @Implements would be cool to.  @SuppressWarning allows to turn certain compiler warnings on which I avoided in the past, because I didn't want warnings for the handful of "special cases" of a warning.&lt;br /&gt;&lt;br /&gt;5. String.contains - Can you believe it?  I feel like a Programmer of the Future every time I use this baby. &lt;br /&gt;&lt;br /&gt;6. OutOfMemory actually TELLS you what kind of memory we ran out of!  Before 1.5, you had to figure out what kind: heap?  perm heap? thread stack?  They were clearly emboldened by the rejoicing of this fix, and tackled an even MORE amazing problem in Mustang: ClassCastException will tell you what was casted! &lt;br /&gt;&lt;br /&gt;7. Thread.getStackTrace/getAllStackTraces.  If you run into race condition/locking problems, and don't have the luxury of reproducing in your IDE, a JSP that displays Thread.getAllStackTraces is pretty useful.&lt;br /&gt;&lt;br /&gt;8. enums - Typesafe enums are essential for clarity in big APIs, and I hope they get more attention now that they're first class in Java.   If you are leary of Generics introducing clutter to API, you won't like this:&lt;br /&gt;public abstract class Enum&lt;e&gt;&gt;&lt;br /&gt;I tried writing a utility method for enums, and it actually set my brain on fire. &lt;br /&gt;&lt;br /&gt;Eclipse has a neat compiler option - to warn/error if a switch statement doesn't cover every member of the enum.  This is a wonderful tool, as you often want to take an action based on the value of an enum, and it's imperative to cover every possible value of the enum.  However, I haven't used switches or breaks since I was a C programmer.   I was torn between the joy of a new compiler warning, and the mess that is "switch".  I tried and tried, and eventually just had to drop the switch.  Its freaky scoping and flow was just too much to swallow.&lt;br /&gt;&lt;br /&gt;9. Monitoring - Anybody who's had problems in production will love JConsole and java.lang.management.ManagementFactory.  You'll also love System.nanoTime if you've ever tried timing operations with System.currentTimeMills.  currentTimeMillis could not measure down to the millisecond, so any "fast" operation would result in times of 0, 16 or 32 milliseconds.  Not a problem with nanos!&lt;br /&gt;&lt;br /&gt;I'm sure I'm forgetting quite a bit, but in short, I'm in love.   Tiger represents a good balance between Sun's traditional conservatism and the pressure they face from their emerging competition.  I hope they maintain their discipline as well as their fear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-113444168067584571?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/113444168067584571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=113444168067584571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113444168067584571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113444168067584571'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2005/12/tiger-beat.html' title='Tiger Beat!'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-113007578473619935</id><published>2005-10-23T06:51:00.000-07:00</published><updated>2009-05-02T06:41:48.734-07:00</updated><title type='text'>i18n zip file woes</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Update: &lt;/span&gt;This is being addressed in &lt;a href="http://blogs.sun.com/xuemingshen/entry/non_utf_8_encoding_in"&gt;JDK7&lt;/a&gt;.  It will still be up to your to figure out what encoding your zip file is in - no small feat if you've got zips coming in from various sources/locales.&lt;br /&gt;&lt;br /&gt;Our app allows customers to upload zip files of content. Recently, customers in Brazil were having problems with a file they were uploading. We'd get this exception when trying to unzip it:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;java.lang.IllegalArgumentException&lt;br /&gt;at java.util.zip.ZipInputStream.getUTF8String (ZipInputStream.java:291)&lt;br /&gt;at java.util.zip.ZipInputStream.readLOC (ZipInputStream.java:230)&lt;br /&gt;at java.util.zip.ZipInputStream.getNextEntry (ZipInputStream.java:75)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;Inspecting the file, I found they were including Portuguese characters in the file name. I was pretty suprised to find this issue was related to not &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4244499"&gt;one&lt;/a&gt;, but &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4415733"&gt;two&lt;/a&gt; of Java's &lt;a href="http://bugs.sun.com/bugdatabase/top25_bugs.do"&gt;Top 25 Bugs&lt;/a&gt;. The Sun engineers point out the unfortunate fact that the Zip spec doesn't say anything about encoding of file names. The only thing Java could do better is allow people to pass in their own encoding when instantiating a ZipFile. A commentor even provides a patch for ZipInputStream to allow this. I found this solution didn't even cut it for me. The customers were using some German zip program (a truly international problem!), and I couldn't get a clean unzip with any encoding. When I discoved both WinZip and Windows XP "compressed folders" feature were baffled as well, I threw in the towel. People waiting for Sun to fix this are probably in for a nasty suprise.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;For the Brazillian customers, I had them re-create the zip using &lt;a href="http://www.mycgiserver.com/%7Eranab/jar/index.html"&gt;a nice little graphical jar utility&lt;/a&gt; - ZipOutputStream uses UTF-8, which will have no trouble with their i18n file names.  Another good alternative would be &lt;a href="http://www.7-zip.org/"&gt;7-zip&lt;/a&gt;, which considered i18n issues from the start.  But, suprisingly, their Java support seems pretty lacking.&lt;br /&gt;&lt;br /&gt;For the grim details of this problem, I can't say it better than the WinZip tech support person:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;&gt;There is unfortunately some ambiguity within Zip files as to the&lt;br /&gt;&gt;character set that the filename is stored in. Whenever a file can be&lt;br /&gt;&gt;stored in the OEM character set (which is the character set originally&lt;br /&gt;&gt;used by MS-DOS), WinZip does so for compatibility with other Zip&lt;br /&gt;&gt;utilities. In this case, it marks the Zip file as made by MS-DOS, since&lt;br /&gt;&gt;the original Zip utilities were DOS utilities that used the OEM&lt;br /&gt;&gt;character set for filenames.&lt;br /&gt;&gt;&lt;br /&gt;&gt;For files whose names can't be stored in OEM, because they contain&lt;br /&gt;&gt;characters not present in the OEM character set, WinZip stores the&lt;br /&gt;&gt;filename in ANSI and marks the file as having been made on an&lt;br /&gt;&gt;NTFS-based system. WinZip is here following the lead of InfoZip, a Zip&lt;br /&gt;&gt;utility that since 1993 used this method of marking filenames as being&lt;br /&gt;&gt;stored in the ANSI character set. (ANSI is the character set used by&lt;br /&gt;&gt;Windows 95, 98, and Me, and by many Windows applications. Windows 2000&lt;br /&gt;&gt;and Windows XP use yet another character set, Unicode, but they also&lt;br /&gt;&gt;provide support for the ANSI character set.)&lt;br /&gt;&gt;&lt;br /&gt;&gt;However, some other Zip utilities handle this differently. In&lt;br /&gt;&gt;particular, Microsoft's Compressed Folders program always marks the&lt;br /&gt;&gt;files it creates as having been made on an NTFS-based system, but&lt;br /&gt;&gt;stores the filename in the OEM character set.&lt;br /&gt;&gt;&lt;br /&gt;&gt;So when WinZip sees a file marked as NTFS-based, it has no way to be&lt;br /&gt;&gt;absolutely sure whether the filename is in the OEM character set (and&lt;br /&gt;&gt;needs to be translated to ANSI), or if it is already in the ANSI&lt;br /&gt;&gt;character set. WinZip uses some complicated heuristics to try to decide&lt;br /&gt;&gt;which character set is involved, and it almost always comes up with the&lt;br /&gt;&gt;"right" answer, but there is no way to be absolutely right in every&lt;br /&gt;&gt;case.&lt;br /&gt;&gt;&lt;br /&gt;&gt;We are looking into how to handle this better in a future version of&lt;br /&gt;&gt;WinZip.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-113007578473619935?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/113007578473619935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=113007578473619935' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113007578473619935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113007578473619935'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2005/10/i18n-zip-file-woes.html' title='i18n zip file woes'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-113000863302155998</id><published>2005-10-22T11:29:00.000-07:00</published><updated>2005-10-22T12:29:23.510-07:00</updated><title type='text'>Crystal ate my log4j!</title><content type='html'>When solving a problem on a live site, logs are indespesnable. So imagine my frustration last spring when I went to solve a problem, and no logs were there. None. Everything had just stopped logging. Solving a problem with access logs alone is not an enviable task. I searched around a bit, and found &lt;a href="http://logging.apache.org/log4j/docs/faq.html#3.6"&gt;this&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I was indeed using the log4j WatchDog to periodically watch log4j.xml for changes. And we do hot restarts of the context from time to time. I wasn't convinced this was the problem, as I could not reproduce the problem no matter what I did with the WatchDog and hot restarts. So I set the system property "log4j.debug" to "true", in the hopes that next time it happened, I'd get some kind of info. I also wrote code that ensured any time a Logger object is acquired, a System.out Console appender was attached to it, at the very least.&lt;br /&gt;&lt;br /&gt;The logs continued to disappear, but thankfully output went to stdout, and was captured. Then, log4j.debug paid off. In the middle of a log, I saw this:&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;log4j: Reading configuration from URL jar:file:/E:/webapps/app/WEB-INF/lib/celib.jar!/META-INF/CrystalEnterprise.Trace/basic.properties&lt;br /&gt;log4j: Parsing for [root] with value=[ERROR, A1].&lt;br /&gt;log4j: Level token is [ERROR].&lt;br /&gt;log4j: Category root set to ERROR&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;Whoah! Sure enough, all of my categories and appenders were blown away at this point. It didn't happen at startup, but whenever the first Crystal report was launched. After much consternation and trying to decipher the log4j comment in the &lt;a href="http://ftp.crystaldecisions.com/webprod/cejavasdk/release.htm"&gt;release notes&lt;/a&gt;, my coworker came up with setting the system property "crystal.enterprise.trace" (yes, not even mentioned in the release notes) to "false". Now we can launch Crystal reports AND use log4j - oh, the decadence!&lt;br /&gt;&lt;br /&gt;I'm no log4j expert, so I wonder how Crystal should have played more nicely here. Surely, there's a away to use PropertyConfigurator to amend logging configuration, rather then obliterate it.&lt;br /&gt;&lt;br /&gt;Lessons learned:&lt;br /&gt;1. Abstract your code such that you can intercept acquisition of Logger objects. Use this code to ensure that a Logger is at least guaranteed to have a Console appender, and escalate the problem if it indeed has zero appenders.&lt;br /&gt;2. Set log4j.debug to true at all times&lt;br /&gt;3. When using crystal, be sure to set crystal.enterprise.trace to true (unless, of course, you care about their logs more than your own).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;pre&gt;&lt;several&gt;&lt;span style="font-family:arial;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/several&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-113000863302155998?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/113000863302155998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=113000863302155998' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113000863302155998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113000863302155998'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2005/10/crystal-ate-my-log4j.html' title='Crystal ate my log4j!'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18170508.post-113000572479404056</id><published>2005-10-22T11:20:00.000-07:00</published><updated>2005-10-22T11:28:44.800-07:00</updated><title type='text'>Microsoft to buy Redhat?</title><content type='html'>I've finally gotten over my fear that I'd create a totally useless, misguided, and confused blog. I've gotten over it - I now know this blog will be be useless, misguided, and confused. My only three goals are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Document weird problems I've encountered in the hopes that I can help someone avoid my frustration&lt;/li&gt;   &lt;li&gt;Have inflamatory titles to attract people to read my blog, and respond to it.&lt;/li&gt; &lt;li&gt; Learn from responses to my posts&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Vent.&lt;/li&gt;&lt;/ul&gt;I'm a Java programmer who has been working on roughly the same product since about 1998. That being said, I won't have many smart things to say about the hot topics of the day: AJAX, RoR, or Web 2.0. I will hopefully be able to share interesting experience on more mundane topics, like JDBC, i18n, webapp performance, maintainable code, and other such things.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18170508-113000572479404056?l=www.tuple23.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tuple23.com/feeds/113000572479404056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18170508&amp;postID=113000572479404056' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113000572479404056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18170508/posts/default/113000572479404056'/><link rel='alternate' type='text/html' href='http://www.tuple23.com/2005/10/microsoft-to-buy-redhat.html' title='Microsoft to buy Redhat?'/><author><name>Adam Rabung</name><uri>http://www.blogger.com/profile/08575207879136726271</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_03sd0WTzAZg/TBjxp9oK3BI/AAAAAAAAKrc/b3Z3lHg3a9U/S220/tb.png'/></author><thr:total>1</thr:total></entry></feed>
