The past month I've been using an open source project called Dropwizard. Dropwizard is a self-described as being a “Java framework for developing ops-friendly, high-performance, RESTful web services”. Dropwizard is an awesome piece of kit that bundles best of breed Java tooling like Jetty, Guava and Jersey. Speaking of Jersey, this is what I'd like to talk about today, specifically about how Dropwizard exposes the ability to create your own Jersey ExceptionMapper and how the built-in Dropwizard ExceptionMappers might cause you some grief, with a workaround.

What is an ExceptionMapper?

Jersey, or should I say JAX-RS, exposes a mechanism that will allow you to map a thrown Exception or Throwable to a REST response, instead of being unhandled and being presented to the user as some stacktrace or error text. (This mechanism requires than you implement the generic ExceptionMapper interface and then register it.) This is excellent for REST APIs that like to return errors back to the client as part of using the API, like returning a JSON representation of an Exception that can be parsed and handled on the client.

Custom ExceptionMappers in Dropwizard

My initial impression of Dropwizard in the context of Jersey and needing to register custom ExceptionMappers was very positive since Dropwizard exposes an API for registering ExceptionMappers. Here is a very brief example for those of you looking to register your custom ExceptionMapper within Dropwizard:

package org.thoughtspark.dropwizard.app;

import org.thoughtspark.dropwizard.app.ApplicationConfiguration;
import org.thoughtspark.dropwizard.app.GenericExceptionMapper;

import com.yammer.dropwizard.Service;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;

/**
 * Example Dropwizard {@link Service}.
 */
public class ApplicationService extends Service<ApplicationConfiguration> {

    /**
     * Entry point for running this services in isolation via Dropwizard.
     *
     * @param args the arguments
     */
    public static void main(String[] args) throws Exception {
        new ApplicationService().run(args);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize(Bootstrap<ApplicationConfiguration> bootstrap) {
        bootstrap.setName("application");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void run(ApplicationConfiguration applicationConfiguration, Environment environment) throws Exception {
        // Register the custom ExceptionMapper(s)
        environment.addProvider(new GenericExceptionMapper());
    }

}

The GenericExceptionMapper being registered will handle all Throwables thrown and return a JSON payload representing the error and its message.

Dropwizards Secret “Gotcha”

Everything was going great until I started using Dropwizard Validation. I noticed that whenever my bean validation failed, instead of seeing a JSON payload of my validation exception, I was always seeing an HTML version of the exception…almost as if I never registered my custom ExceptionMapper, or maybe my custom ExceptionMapper just wasn't working. Seeing that all Exceptions extend Throwable, I didn't see how my ExceptionMapper wasn't configured properly so I dropped into the debugger.

After some looking around, I see that the actual exception being throw was of type InvalidEntityException. At this point, I created a new ExceptionMapper specifically for the InvalidEntityException, restarted Dropwizard and it worked! Instead of the HTML responses for InvalidEntityExceptions, I saw my JSON representation. Everything was working great…that is until I restarted the server for a different reason and I noticed that the InvalidEntityExceptions had gone back to HTML. I knew I hadn't changed anything related to the ExceptionMapper so I started debugging. After being unable to get the debugger to hit any break points in my ExceptionMappers I started looking into the Dropwizard sources, thank goodness for open source software, and that is when I saw something, Dropwizard is registering its own ExceptionMapper for the InvalidEntityException. What was still bugging me was why my ExceptionMapper worked once and upon server restart it stopped working, without any changes to my code. Once again I found myself in the bowels of Dropwizard's source and that's when I found my problem.

Dropwizard is adding its custom ExceptionMappers into Jersey's singletons Set, a Set that does not guarantee order. This explains why one time my ExceptionMapper would work and another time, the built-in Dropwizard ExceptionMapper would work. Now that we know the problem, below is one way to work around the problem:

package org.thoughtspark.dropwizard.app;

import org.thoughtspark.dropwizard.app.ApplicationConfiguration;
import org.thoughtspark.dropwizard.app.GenericExceptionMapper;

import com.fasterxml.jackson.jaxrs.json.JsonParseExceptionMapper;
import com.sun.jersey.api.core.ResourceConfig;
import com.yammer.dropwizard.Service;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;
import com.yammer.dropwizard.jersey.InvalidEntityExceptionMapper;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Example Dropwizard {@link Service}.
 */
public class ApplicationService extends Service<ApplicationConfiguration> {

    /**
     * Entry point for running this services in isolation via Dropwizard.
     *
     * @param args the arguments
     */
    public static void main(String[] args) throws Exception {
        new ApplicationService().run(args);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize(Bootstrap<ApplicationConfiguration> bootstrap) {
        bootstrap.setName("application");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void run(ApplicationConfiguration applicationConfiguration, Environment environment) throws Exception {
        // Remove all of Dropwizard's custom ExceptionMappers
        ResourceConfig jrConfig = environment.getJerseyResourceConfig();
        Set<Object> dwSingletons = jrConfig.getSingletons();
        List<Object> singletonsToRemove = new ArrayList<Object>();

        for (Object s : dwSingletons) {
            if (s instanceof ExceptionMapper && s.getClass().getName().startsWith("com.yammer.dropwizard.jersey.")) {
                singletonsToRemove.add(s);
            }
        }

        for (Object s : singletonsToRemove) {
            jrConfig.getSingletons().remove(s);
        }

        // Register the custom ExceptionMapper(s)
        environment.addProvider(new GenericExceptionMapper());
    }

}

In the code above, I remove all Dropwizard ExceptionMappers so that I have complete control over how my application renders Jersey Exceptions. Now no matter how many times I restart the server, my custom ExceptionMapper will be used and I can always expect JSON to be returned for Exceptions thrown on the server. Of course, you might need to change the approach above based on your needs but for this scenario, I just wanted any ExceptionMapper that Dropwizard provided to be done away with so I could use my custom versions that returned JSON instead of HTML.

Conclusion

Dropwizard is awesome and anytime I have to write Java-based REST servers, I'll be using it. I do question the built-in ExceptionMappers, especially with their inability to be configured to output something other than the hardcoded HTML, but with the workaround above, I don't have to be stuck because of them. Please do not let this take away from Dropwizard and if you get tired of having to use the workaround above, I'm sure the team would welcome a patch…if you beat me to it.


I was going through my Google Reader stream today when I came across a thread that bothered me: Borderlands 2’s Writer Says He’ll Change Tiny Tina If She Conveys Racism, As Some Players Think. After reading the thread, I was shocked at the accusation myself. I remember playing Borderlands 2 with a good friend of mine a few days after the release and not only enjoying the Tiny Tina character but laughing so hard I was crying. I love Tiny Tina and I just cannot see how she or the person behind her (Anthony Burch), could be considered racist. I would had left it at a simple reply to Anthony on Twitter supporting him and Gearbox Software but feeling that there is so much more to this than 140 characters can say, I figured I'd weigh in here.

What is Racism?

Racism, as defined by Merriam-Webster, is as follows:

Any action, practice, or belief that reflects the racial worldview—the ideology that humans are divided into separate and exclusive biological entities called races, that there is a causal link between inherited physical traits and traits of personality, intellect, morality, and other cultural behavioral features, and that some races are innately superior to others.

That being said, where in the description above does it say that someone of one race using the lingo of another race is racism, or that a race could even impose ownership of lingo? The idea of saying that Tiny Tina's character is racist because she uses “black lingo” is a joke, although not a laughing matter because it's ridiculous accusations like this that fuel the controversal matters of racism. Could you imagine calling Eminem, one of the most talented rappers ever to grace a microphone, a racist because he's white and uses “black lingo” in his raps?

My Opinion

In my personal opinion, I think the idea of suggesting that lingo could be owned by a race could be considered racist. I mean, suggesting that people of a certain race are the only ones to use certain words is a race-based stereotype, much like what is described above. Having grown up in Georgia myself, I knew quite a few white girls/guys that used black lingo and black girls/guys that used white lingo. To us, they were just words. As long as you stayed away from the derogatory words/phrases commonly referred to as racial slurs, you used whatever verbiage best fit who you were with and the context of the conversation regardless of which race used the verbiage most or coined a particular word/phrase.

What did Gearbox say about the matter? Here is Gearbox President Randy Pitchford's response on Twitter:

@reverendanthony tina is not racist because you are not racist. You're a pillar of tolerance and inclusion.

In Conclusion

Borderlands 2 is an awesome game and Tiny Tina is one of my favorite game characters of all times. Like many others, I find her hilarious and did not even think of the race card while enjoying the parts of the game she was in. I think Anthony did an excellent job making Tiny Tina quirky, unique and memorable, all the things you'd want from a gaming character. I also applaud his handling of the situation linked to above. In the end, I wish him the best and I hope that people can stop trying to make something out of nothing, the world is already destructive enough without outlandish accusations about very sensitive subjects such as racism.


Let's make it official, in case you didn't hear on Twitter, I've signed a contract with O'Reilly Media to write a book about Underscore.js. How did I get into this awesome situation you might ask? Well, back in October Jeremy Ashkenas posted on Twitter saying that if you were interested in writing a book about Underscore.js, let him know. I submitted my proposal and it was accepted. WOOHOO!!! Needless to say, I'm very excited about this opportunity and I'll do my best to make sure this thing happens.

Any Suggestions?

I'm not looking to have my name on the cover of just any book, I want this book to be the best possible. That being said, I'd love to hear anything you think that could help make the book awesome. To submit your suggestions, leave your requests/suggestions in the comments below.

Progress

I've already started work on this book based on the proposal sent to O'Reilly. As I make progress, I'll keep you guys up to speed here on ThoughtSpark.org. Feel free to reach out to me on Twitter or in the comments with anything pertinent to this effort.


I've decided it's time to rethink how I maintain and deploy ThoughtSpark.org. My current deployment model is to use Drupal to craft/host my site's content and I currently pay a small monthly fee to GoDaddy for hosting Drupal. While there isn't anything really wrong with my current model, I've grown tired of it. Below are a few pain points worth mentioning.

Maintenance Overhead

I've grown tired of maintaining Drupal. I'm tired of applying a security patch or verision update and having my whole site turn to crap. Why? All of my modules then need to be re-enabled and/or updated. How is this a problem? All non-core functionality on my site (sitemap.xml generation, SPAM filtering, syntax highlighting, …) are all enabled via modules. If these modules are disabled during the update, and they are, I now have to go through the process of re-enabling them just so my site doesn't look like crap and I don't get SPAMed to Hell and back.

Don't get me wrong, Drupal is a phenomenal product. It's an excellent CMS and Drupal is also a great example of what an OSS project should be. It's not Drupal's fault that I don't need a CMS and I'm sure there is a reason that the update process is more painful than I'd like.

Another aspect of the maintenance overhead is the fact that Drupal runs on PHP and needs a database, MySQL in my case, so you have to either host your server or pay someone to host it you. I chose the second option. The overhead for this of course is the financial cost, regardless of how large or small it is.

Authoring

The options I've been exposed to in Drupal for authoring content on my site is to use raw HTML or using one of the WYSIWYG editors. The problem with raw HTML is it's cumbersom and error prone. Crafting a single post can often end up with a lot of time spent finding HTML typos. The problem with WYSIWYG editors is that you often end up fighting them. Either the output is junk or they don't handle certain use cases, like handling code blocks. Regardless, I loathe creating content in Drupal but again, I don't feel it's Drupal's fault, I just want something simpler.

One approach to creating web-based content I've become very fond of as of late is Markdown. Markdown is a great language that allows me to focus more on the content being crafted while still being able to style my content very easily. I can even drop in raw HTML wheenver I feel the need to. If you've ever visited any GitHub project/user homepage or a project's wiki, you've seen the result of Markdown.

The Solution

The new ThoughtSpark.org will no longer be using Drupal and will no longer be deployed on GoDaddy. Instead, I'm going to use a static website generator that will take my Markdown files and create my website. The tool I will be using is Middleman and I will be using GitHub Pages as my host. Not only will writing/maintaining my website content be easier but now it will also require no cost to host. Those two things are good enough reasons for me to switch but there are also the following reasons that are equally compelling:

  • Security: With there being no server-side component and no server-side processing, there are much fewer security issues that I need to concern myself with
  • Performance: With there being no server-side component and no server-side processing, the performance of the site will be faster
  • Deployment: The solutions for hosting static websites are plentiful and you are no longer locked into a particular host/product for hosting your website. (There's a chance you're already using a service that will host your static websites for you. Examples: GitHub's Pages and DropBox are two excellent examples.)

In Closing

GitHub Pages, Markdown, Middleman and Twitter Bootstrap have made it very easy for me to re-create and maintain ThoughtSpark.org. I feel like with this new approach for ThoughtSpark.org, I'll be able to get posts out quicker and much easier, while saving a few bucks along the way. Thanks for your patience and I look forward to sharing with you on my new platform.

Note: There are a few things left to finish before I'd say that the migration is complete, follow here if you're interested.

Note: Originally I had planned on migrating all of the old Drupal posts to the new platform. I've decided against it for a few reasons and will instead only migrate things upon request. To request such a thing, use the issue tracker or hit me up on Twitter.