play-plugins icon indicating copy to clipboard operation
play-plugins copied to clipboard

JedisPool is null when trying to inject in another class than the controllers

Open johdah opened this issue 10 years ago • 6 comments

I am able to inject the JedisPool in my controllers but not in models, daos or other classes. An example is in my UserDAO. Isn't this supported or why does the exact same code work in the Application controller?

...
import javax.inject.Inject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class UserDAO extends AbstractDAO<User, User_> {
    @Inject JedisPool jedisPool;

    public UserDAO() {
        super(User.class, User_.class);
    }

    /**
     * @return an instance of {@link UserDAO}.
     */
    public static UserDAO newInstance() {
        return new UserDAO();
    }

    ...

    // -- Redis

    /**
     * Get the last time the user accessed the service.
     *
     * @param user the {@link models.User}
     * @return the last time as a {@link org.joda.time.DateTime}
     */
    public DateTime getLastAccess(User user) {
        if(jedisPool == null) {
            Logger.error("Redis is not available");
            return null;
        }

        Jedis j = jedisPool.getResource();
        DateTime dateTime = null;

        try {
            String dtString = j.hget("userLastAccess", user.id.toString());
            dateTime = new DateTime(Long.valueOf(dtString));
        } catch(NumberFormatException ex) {
            dateTime = null;
        } finally {
            jedisPool.returnResource(j);
        }

        return dateTime;
    }
}

johdah avatar Jul 09 '15 12:07 johdah

In order for @Inject to work elsewhere, that class need to also participate in the dependency injection tree. Play2 uses Guice internally so this is what you need to do:

In application.conf:

play.modules.enabled += "modules.yourModule"

create a new class your module:

 package modules;
 import com.google.inject.AbstractModule;

 public class yourModule extends AbstractModule {
    @Override
    protected void configure() {
        //add configuration logic here
        bind(yourDaoInterface.class).to(yourDaoImplementationClass.class);
    }
 }

This way when your Dao class is instantiated by Guice, it'll look through all annotations and inject the Dao's dependencies as needed.

If you need to learn more about Dependency Injection in general or Guice in particular, watch Bob Lee's video on Guice

ronaldwidha avatar Jul 16 '15 13:07 ronaldwidha

So I need to create an interface for every DAO class I have and then create a DAOModule where I add a bind for every DAO class?

johdah avatar Jul 16 '15 14:07 johdah

Yes. The module is application-wide as far as I know, where all your binding lives. Not just for the DAOs but any other class where you want to use Guice @inject

ronaldwidha avatar Jul 16 '15 16:07 ronaldwidha

i tried the solution but still gives me null.

mmadian avatar Aug 19 '15 15:08 mmadian

@mmadian why dont you share some code

ronaldwidha avatar Aug 19 '15 17:08 ronaldwidha

@mmadian The problem is likely that you don't inject the class because then it doesn't matter if you have an @Inject. Here is my working code:

UserDAO:

public class UserDAO extends AbstractDAO<User, User_> {
    JedisPool jedisPool;

    @Inject
    public UserDAO(final JPAApi jpaApi, JedisPool jedisPool) {
        super(jpaApi, User.class, User_.class);
        this.jedisPool = jedisPool;
    }

    /**
     * Get the last time the user accessed the service.
     *
     * @param user the {@link models.User}
     * @return the last time as a {@link org.joda.time.DateTime}
     */
    public DateTime getLastAccess(User user) {
        if(jedisPool == null) {
            Logger.error("UserDAO - getLastAccess - Redis is not available");
            return null;
        }

        Jedis j = jedisPool.getResource();
        DateTime dateTime = null;

        try {
            String dtString = j.hget("userLastAccess", user.id.toString());
            dateTime = new DateTime(Long.valueOf(dtString));
        } catch(NumberFormatException ex) {
            dateTime = null;
        } finally {
            jedisPool.returnResource(j);
        }

        return dateTime;
    }
}

And then you load UserDAO like this:

UserDAO userDAO = play.Play.application().injector().instanceOf(UserDAO.class);

johdah avatar Aug 20 '15 07:08 johdah