How generics can pay dividends

One of the things I’ve noticed lately are some discussions regarding how cumbersome generics can be. They can take time to get right or figure out and some folks have gone as far as to stipulate that if you can’t do it without generics then something is borked.

While reading a lot of this, I’ve also being writing the MVC for JCatapult. I’m a big generic fan and I’m on the opposite side of the fence from a lot of the folks that have been generic bashing lately. I think that if you can’t get rid of all the unchecked warnings and use generics everywhere, you’re probably not doing something correctly. Of course this isn’t always possible, but I try to get there.

I’ve done some Rails work and some Grails work over the past few years. When it comes to dynamic languages, you are almost always getting the incoming HTTP request parameters into your actions as simple Strings. Therefore, if you want to do some math or pass them along, you might have to convert them a bit. This is how most first generation Java MVCs also worked. A few more modern MVCs did it a bit better. Struts2 for example uses OGNL and can populate JavaBeans with the values using a specific syntax like this:

user.address.city

These MVCs also go so far as to provide type conversion support. If you have an action like this:

public class MyAction {
  private int age;

  public int getAge() {...}
  public void setAge(int age) {...}
}

you can pass in the age parameter and the MVC will convert it to an integer. Most of these also handle type conversion failures decently well. Here is an example URL:

http://www.example.com/my-action?age=42

In many cases, these more modern MVCs will also instantiate classes for you and set them into JavaBean properties. The user.address.city example might map to this code (getters and setters have been left out):

public class MyAction {
  private User user;
}

public class User {
  private Address address;
}

public class Address {
  private String city;
}

Since the MyAction member variable named user is null, the MVC will instantiate the User class and set it into the MyAction class. Most of these MVCs hit a limitation when it comes to complex object modeling that uses collections. One of the main reasons is that from a legacy perspective (i.e.JDK 1.4) it was impossible to know what types of objects were being stored in a collection. Here’s an example:

public class MyAction {
  private User user;
}

public class User {
  private Map addresses;
}

public class Address {
  private String city;
}

There was no way for the MVC to understand that the Map contains addresses and that the keys are Strings like home and work. However, if you changed this code like this:

public class MyAction {
  private User user;
}

public class User {
  private Map<String, Address> addresses;
}

public class Address {
  private String city;
}

some modern MVCs can figure it out. The issue is that they don’t do a good job and many times fail horribly. So, I decided for JCatapult to fix this. JCatapult supports all flavors of generic programming when it is converting HTTP request parameters into objects. It supports arrays, Collections, Lists, Sets, SortedSets, Queues, and Maps. It also handles nested collections like:

Map <string , List<map> crazyAddresses;

It also supports handling multiple request parameters of the same name and converting them into generic collections. Let’s say you want to pass in a list of IDs using checkboxes like this:

<input type="checkbox" name="ids" value="1"/>Choice 1
<input type="checkbox" name="ids" value="2"/>Choice 2
<input type="checkbox" name="ids" value="3"/>Choice 3

These will come into the Servlet container as a single parameter that is an array of Strings. Your action can then look like this:

public class MyAction {
  private Set ids;
}

You could also nest these IDs inside another class. The nice thing about this is that using generics can reduce the amount of code you have to write to get access to a Set of Integers.

So, the moral of the blog post, generics are good things and can reduce overhead considerably.

7 thoughts on “How generics can pay dividends

  1. Good point Brian, but IMHO, I think, the moral is type information is very useful at times and should be inferred. Generics is one way to get that, and makes it useful for the purpose you’ve mention, but that does not necessarily make Generics good. Can you get that type information/inference in other ways, like annotations or something lightweight that may be created in the future?

    Like

  2. Sure. Annotations might help out, but I’m not certain that I want to place an annotation on every field. The key is to reduce code without introducing complexity. A major reason some languages haven’t taken off really big. You would have to annotate even simple primitives like this

    @Integer
    var age

    What’s the difference between that and just defining the type? Nothing as far as I can tell.

    I just don’t see the bad in generics. I guess I haven’t been convinced that 99.9% of everyday generic usage is bad. I understand that some generics can be a little bit hairy, but that complexity is usually left to the platform and framework developers who can grok it.

    The only way I could see it improving would be to make the syntax simpler and to hide complexity. The issue seemingly always comes back to type determination by tools. Can a tool determine the types in a collection? If you have a String[], can you convert it to a List<integer>

    Like

  3. In the specific instance of Brian’s examples, generics were clearly the way to go.

    Abuse of annotations is fairly rampant IMO. Use them conscientiously.

    Like

  4. I want a Generics implementation without type erasure! Till then, Java’s Generics implementation is half-baked and broken.

    Like

  5. @Van der Shart: I think everyone who uses generics wants an implementation without type erasure, but until we get that, the erasure-based generics are the best thing we have and still better than nothing. I prefer what is described by some generics antagonists as cumbersome type annotations to a rampant use of casts.

    And while we are talking about generics without type erasure, perhaps you will allow me to mention NextGen, a javac compiler replacement developed at Rice University that allows first-class generics: http://japan.cs.rice.edu/nextgen/

    Like

  6. Hey Brian,
    Did you update OGNL to handle generics? Or did you end up using something else? When I tried to create generic actions in S2, OGNL ended up not knowing how to set the types. Ie, I create a GetAction and a generic entity T on the object is now set with the correct params.

    Like

  7. @Gabriel

    I agree with respect to annotations. This is another reason I’m writing yet another MVC. Struts2 and XWork annotations are now just as bad as the XML configuration, especially for validation! JCatapult’s MVC is pretty lightweight with annotations and more importantly they aren’t generalized annotations like many other frameworks use. For example, Struts2 uses a single annotation for all Results including forwards, redirects, streams, xml, etc. JCatapult uses mutliple annotations such as Forward, Redirect, Xml, Stream, etc. Each annotation contains the parameters that make sense for that result type.

    @Van der Shart

    Yeah, everyone wants this. There is some good work going on at Sun for JDK 7 that will make generics much better in this respect. I forget the exact person working on it, but hey has some great ideas to “fix” erasure.

    @Mathias

    I’ll definitely check out nextgen. Sounds very cool. The biggest issue will still be the single instance of a Class per Classloader regardless of the type parameters used. AFAIK the majority of the issues aren’t in the compiler, but in the JVM.

    @Blake

    I ran into the exact same situation and since XWork and Struts are coupled to OGNL completely and I’m not an XWork or OGNL committer, I couldn’t do anything about it all really. Plus, OGNL is overly complex because it is an entire expression language. I didn’t need an entire EL to start, just something for setting parameters into the actions So, I wrote my own solution. The nice thing about this solution is that it doesn’t use any lexer/parser and correctly handles generics, even some of the more tricky cases. If you want to take a look, check out the code from the Google code project. It is at http://jcatapult.googlecode.com/svn/jcatapult-mvc/trunk in a package named org.jcatapult.mvc.pamareter.el

    Like

Leave a comment