Help with Guice Hibernate Module

61 views
Skip to first unread message

rakstar

unread,
Mar 26, 2007, 11:58:19 PM3/26/07
to google-guice
I'm working on a Guice module to simplify working with hibernate.
What I have now already does so to a degree (zero mappings / xml's /
redundant DAO interfaces and abstract classes), but I feel like it can
be simplified even further, except, I'm not sure how (or if it's even
possible) to accomplish what I want.

Here's how my module works currently:

1. I create an injector with my custom hibernate module:

GuiceHibernateModule guiceHibernateModule =
new GuiceHibernateModule( new Class[] { User.class,
Item.class } );

* this module takes the array of classes (User.class, Item.class),
creates an AnnotationConfiguration, and binds a SessionFactory


2. I add a second module with the following bindings:

binder.bind(new Key<HibernateDao<User, Long>>() {})
.toInstance(new AbstractHibernateDao<User, Long>() {});
binder.bind(new Key<HibernateDao<Item, Long>>() {})
.toInstance(new AbstractHibernateDao<Item, Long>() {});

* HibernateDao is my DAO interface
* AbstractHibernateDao is the HibernateDao implementation
* User/Item - the hibernate pojo type
* Long - the primary key type


3. then in my code, i access my DAO with the following:

HibernateDao<User, Long> userDao =
injector.getInstance(new Key<HibernateDao<User, Long>>() {});

User user = new User();
user.setUsername("test");

Long id = userDao.save(user); // save the user
userDao.delete(user); // delete the user


Here's what I'm trying to figure out: I'd like get rid of step #2 by
dynamically creating it as part of my custom hibernate module in step
#1. I'd like to dynamically create the bindings based on the array of
classes that are passed into the module.

ex:
public GuiceHibernateModule(Class[] pojos) {
this.pojos = pojos;
}

...

for (Class pojo : pojos) {
binder.bind(new Key<HibernateDao<pojo, Long>>() {})
.toInstance(new AbstractHibernateDao<pojo, Long>() {});
}


Does anyone know if this is possible? If not, is there something that
Guice can do to address this?

I hope I illustrated my point clearly. If anyone is interested in
obtaining my code, please contact me. I have the project set up with
Maven2 and a JUnit test.

Thanks.

Dhanji R. Prasanna

unread,
Mar 27, 2007, 2:48:27 AM3/27/07
to google...@googlegroups.com
On 3/27/07, rakstar <rak...@gmail.com> wrote:


    for (Class pojo : pojos) {
        binder.bind(new Key<HibernateDao<pojo, Long>>() {})
            .toInstance(new AbstractHibernateDao<pojo, Long>() {});
    }


Does anyone know if this is possible?  If not, is there something that
Guice can do to address this?

No, you cannot declare a parameterized type with a variable. Partly because java generics are erased at compile time, what you are asking for is not directly possible.

One would think this syntax would work (but it doesnt):

public <T> static void bindDao(Class<T> pojoClass, Binder binder) {
   binder.bind(new TypeLiteral<HibernateDao<T>>() { }).toInstance(....);
}


What you really need to do is use data available at runtime to discriminate the target types. What I do is to use providers to obtain the dao and simply make an unchecked cast (after all the underlying code is the same) with an @SuppressWarnings. If your dao is threadsafe you can bind it in the singleton scope to save on memory.

rakstar

unread,
Mar 27, 2007, 8:17:52 PM3/27/07
to google-guice
Thanks for you reply. I finally found a solution using your
suggestion as a starting point. Here's what I came up with:

private static Map<Class, Key> keyMap = new HashMap<Class, Key>();

private <T> void bindDao(Class<T> clazz, Binder binder) {
binder.bind(getKey(clazz))
.toInstance(new AbstractHibernateDao<T, Long>() {});
}

@SuppressWarnings("unchecked")
public static <T> Key<HibernateDao<T, Long>> getKey(Class<T>
clazz) {
if (!keyMap.containsKey(clazz)) {
Key<HibernateDao<T, Long>>key = new Key<HibernateDao<T,
Long>>() {};
keyMap.put(clazz, key);
}
return keyMap.get(clazz);
}

I used a map to cache my Keys because creating a new key for the
instance lookup doesn't work (probably because it returns a different
hashcode/TypeLiteral).
So now to get a DAO instance, all I do is:

HibernateDao<User, Long> userDao =

injector.getInstance(GuiceHibernateModule.getKey(User.class));

and all is good! Thanks again for your help Dhanji.

If there's any interest, I'd like to contribute this as a 3rd party
module. It would be nice to get some help from the community. In the
meantime, I'll continue to work on it for my personal projects.


On Mar 27, 2:48 am, "Dhanji R. Prasanna" <dha...@gmail.com> wrote:

Reply all
Reply to author
Forward
0 new messages