[java-2.5] Dependency Injection fails

737 views
Skip to first unread message

Johan Dahlberg

unread,
Jul 4, 2016, 1:47:23 PM7/4/16
to play-framework
I have upgraded my project to 2.5 and rewritten everything to use Dependency injection but in most places the injection fails and result in Null pointer exception. In this example jpaApi will be null when it's used in onReceive.
I have a delay in the module that starts the actors to make sure that everything is initialized in the project. Is this a common problem? It looks like some injections work but not all.

package actors;

import akka.actor.UntypedActor;
import dao.notification.NotificationDAO;
import java.util.List;
import javax.inject.Inject;
import models.notification.Notification;
import play.db.jpa.JPAApi;

public class NotificationsActor extends UntypedActor {
    @Inject
    JPAApi jpaApi;

    @Inject
    NotificationDAO notificationDAO;

    @Override
    public void onReceive(Object message) throws Exception {
        jpaApi.withTransaction(() -> {
            // Check if any new notifications have been received
            List<Notification> notifications = notificationDAO.findAllUnsentNotifications();

            try {
                for (Notification notification : notifications) {
                    notification.sendMail();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
    }
}





Justin Nichols

unread,
Jul 4, 2016, 2:02:50 PM7/4/16
to play-framework
The one thing most people seem to not realize with Dependency Injection is that it requires dependencies to be loaded via a module or the built-in convention of a Controller.

You can't just add @Inject to a variable or to a constructor and expect it to work.  The only way it will is if the containing class extends Controller or if the containing class is bound within a custom module.


Sadly some of the code examples will make people think that things can be willy nilly inject.  This is far from the case.  Everything you wish to inject must be bound in a module at some point, and everything you wish to inject into must be a component bound in a module or one that extends a play Controller.

This has been my experience and is most certainly not all encompassing.  I hope it helps some.

Thanks,

Justin Nichols

_____________________________
From: Johan Dahlberg <jo...@dahlberg.co>
Sent: Monday, July 4, 2016 1:47 PM
Subject: [play-framework] [java-2.5] Dependency Injection fails
To: play-framework <play-fr...@googlegroups.com>
--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/93a04ab9-3872-4269-a3f1-d84c0f8875f6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Johan Dahlberg

unread,
Jul 7, 2016, 8:53:57 AM7/7/16
to play-framework
Thx, do you know if I need to bind all the play stuff like JPAApi manually as well? Since that's the thing that fails in this case.

/Johan

Christian Schmitt

unread,
Jul 7, 2016, 10:10:38 AM7/7/16
to play-framework
Actually just try Constructor Injection: 
public class NotificationsActor extends UntypedActor {
    private final JPAApi jpaApi;
    private final NotificationDAO notificationDAO;
    public NotificationsActor(@Inject JPAApi jpaApi, @Inject NotificationDAO notificationDAO) {
        this.jpaApi = jpaApi;
        this.notificationDAO = notificationDAO;
    }

    // Your code here

)

Ala Schneider

unread,
Jul 21, 2016, 3:06:02 AM7/21/16
to play-framework
There is no difference between field or constructor injection - the result is the same. I guess that UntypedActor is not injected by Play, so you should use explicit injector instead of annotations:

     private JPAApi jpaApi= Play.current().injector().instanceOf(JPAApi.class);
     private NotificationDAO notificationDAO = Play.current().injector().instanceOf(NotificationDAO.class);

You can read more here

Greg Methvin

unread,
Jul 21, 2016, 4:09:32 AM7/21/16
to play-framework
Hi Ala,

That may work, but it's not the proper way to use dependency injection. It's much better to only depend on the components you need rather than requesting something from the injector directly. In fact, the reason Play.current is deprecated now is that it introduces an implicit dependency on the entire application, which is usually not what you want.

The whole point of DI is inversion of control. Your components, including actors, should only declare the dependencies they need, and those dependencies are passed into them, either manually or via the DI framework.

The difference between constructor and field injection is also significant: constructor injection forces manual instantiation of your class to also provide the dependencies at compile time. This means if I were to write a unit test for that component in which I manually create it (potentially with mock dependencies), the compiler will help make sure I've done so correctly.

We do have documentation on dependency injecting actors that may be helpful. Play provides a few helpers to make it easier to set up the bindings with Guice.

Greg


For more options, visit https://groups.google.com/d/optout.



--
Greg Methvin
Senior Software Engineer

Ala Schneider

unread,
Jul 21, 2016, 5:09:29 AM7/21/16
to play-framework
Hi Greg, thank you for your comments.
1. I would like to use DI in the proper way.This solution is for a class, that is not injected.
2. You are write that constructor injection  is better practice, I meant that the result is the same: if a class is has not injection binding, using of constructor injection will not help.
3. The link you have mentioned is for Scala. The original question was about java. I found the relevant link. It is good to know, that the proper DI may be done. 

Greg Methvin

unread,
Jul 21, 2016, 5:37:27 AM7/21/16
to play-framework
HI Ala,

On Thu, Jul 21, 2016 at 2:00 AM, Ala Schneider <ala.sc...@gmail.com> wrote:
1. I would like to use DI in the proper way.This solution is for a class, that is not injected.

Well, the question you should ask here is: why can't this class have its dependencies injected, or otherwise passed to it? Making a request directly to the injector should only be used as a last resort, and if you are migrating an existing application there are solutions that don't force a dependency on the whole application, such as static injection.

By the way I think your blog post is otherwise great, but it kind of glosses over this issue of classes that are "not injected". This is a situation that usually can and should be avoided.

2. You are write that constructor injection  is better practice, I meant that the result is the same: if a class is has not injection binding, using of constructor injection will not help.

Well, my point is that if you're using constructor injection, you can think about the DI framework as just a way of automating what you already do manually, so it's a bit easier for beginners to understand how things work. I've noticed a lot of people who are new to DI in Play seem to think that there is some "magic" going on that lets them instantiate a class normally and have the members injected (including static members). We had initially used field injection in the Java docs for Play, but later realized it wasn't such a good idea for that reason.
 
3. The link you have mentioned is for Scala. The original question was about java. I found the relevant link. It is good to know, that the proper DI may be done.

Thanks. I should've posted the Java docs for that.

Anyway, like I said, I think your blog post is great, and offers some nice suggestions. I just wish you expanded upon why you would want to query the injector directly and offered some alternatives there, especially since Play.current will be removed in a future Play release.
 

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages