1

When I try to mock a Dao using Jukito I get the following exception:

java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
    at org.jukito.JukitoModule.addKeyDependency(JukitoModule.java:338)
    at org.jukito.JukitoModule.addInjectionPointDependencies(JukitoModule.java:330)
    at org.jukito.JukitoModule.addDependencies(JukitoModule.java:313)

The object I try to mock is a ConcreteDao.

public class ConcreteDao extends AbstractDao<MyDomain> {
}

public abstract class AbstractDao<T extends DatastoreObject> {
}

I read several posts on SO about this binding generics but I can't figure out a way to use TypeLiteral for my binding.

This is what I tried:

bind(new TypeLiteral<AbstractDao<MyDomain>>(){}).to(ConcreteDao.class);
durron597
  • 31,968
  • 17
  • 99
  • 158
Sydney
  • 11,964
  • 19
  • 90
  • 142
  • 1
    Can you elaborate in your question? It is not clear what exactly is the problem. – Edwin Dalorzo Mar 23 '12 at 23:57
  • I reformulated the question. Hope it's better – Sydney Mar 24 '12 at 09:10
  • Not really. I don't know Jukito and I might not be alone, could you post a JUnit test explaining where is exactly the issue :) – bric3 Mar 25 '12 at 17:02
  • 1
    I reworked my code to mock interfaces instead of classes. It's working now. The good thing is that my code is now cleaner ;) – Sydney Mar 25 '12 at 18:14
  • I'm not familiar with Jukito in particular, but upon first glance this sounds like a bug (or bad error reporting ;) ). Out of curiosity, if you do `bind(new TypeLiteral>(){}).to(new TypeLiteral(){});` instead, does it work? Looking at the JukitoModule source, it looks like it's expecting the `TypeLiteral`'s `Type` to be a `ParameterizedType` when it happens to be a `Class` (not a safe assumption, apparently). If you can create a small test to reproduce the bug, I'd file a bug with the Jukito project. – Andrew McNamee Jun 10 '12 at 12:55

1 Answers1

3

You need to bind like this:

bind(new TypeLiteral<AbstractDao<MyDomain>>(){}).to(new TypeLiteral<ConcreteDao<MyDomain>>(){});

This is how you can retrieve the generic class:

class AbstractDao {
  protected final Class<T> clazz;

  @Inject
  public AbstractDao(TypeLiteral<T> type) {
    clazz = (Class<T>) type.getRawType();
  }
}

Subclasses of AbstractDao will need to pass entity specific TypeLiterals to the parent class (AbstractDao):

class ConcreteDao extends AbstractDao<MyDomain> {
  @Inject
  public ConcreteDao(TypeLiteral<MyDomain> type) {
    super(type);
  }
}

Note that you can make your AbstractDao class non-abstract and implement basic CRUD operations, so that you can use it without the need to extend AbstractDao for each entity. You will just need a binding for each entity like this:

bind(new TypeLiteral<GenericDao<User>>(){}).in(Scopes.SINGLETON);

See my blog-post for more information.

Jamol
  • 2,281
  • 2
  • 28
  • 28