views:

51

answers:

2

I've been playing around with getting rid of DAOs in favor of ActiveRecord like entities in Java, but generics won't allow me to have the full functionality that I want (like static finders). Somehow Groovy does, but I'm confused why. Given the following:

class ActiveRecord<T> {
   static Class<T> genericType;
   ActiveRecord() {
     genericType = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
   }
   static T find(Serializable id) { return EntityManagerHolder.find(genericType, id); }
   void save() { EntityManagerHolder.persist(this); }
}

@Entity @Table(name="TEST")
class FakeTable extends ActiveRecord<FakeTable> {
   @Id @GeneratedValue(strategy = GenerationType.AUTO)
   Long id;
   String status;
   String type;
   static void main(args) {
      FakeTable t = new FakeTable();
      t.status = "TESTING";
      t.save();
      println FakeTable.find(t.id);
   }
}

This code works (with the JPA stuff that's excluded), but I'm not sure why I'm able to declare

static Class<T> genericType;

Does the compiler do some magic before the actual Java class is compiled? Maybe the groovy compiler is replacing T with the actual class name in the generated Java class?

In strictly Java, I can access the generic type from the find method return type and the class declaration, but both are erased to Object. That makes sense, and Groovy does the same, but in Java, the above line errors out with a message similar to 'Cannot reference non-static T'.

A: 

Groovy is not statically typed. I think you'll find it erases the T at compile time, and doesn't even bother to work out that it's not in scope; it's just irrelevant to Groovy.

Ricky Clarkson
Good to know! I haven't done much groovy dev. Looks like I need to read up a bit more.
hisdrewness
A: 

The main problem that you will run into is that in Java and in Groovy, static methods are NOT inherited. Grails (and other Java frameworks) get around this problem by manipulating byte-code to generate those methods at runtime.

Using groovy, at program start up you could try looping through all the ActiveRecord subclasses and attaching the static finders to their meta class. If you use the ActiveRecord class both to find the sub-classes and to get the static finders at least you can still tell what methods they inherited by looking at the ActiveRecord class itself.

EDIT:

It occurred to me that you could also implement methodMissing on the ActiveRecord class to try to look for the method in on the ActiveRecord object instead. You would just have to be careful not to setup an infinite loop.

Blacktiger