5

I want to use a DAO in my RESTful service developed with Jersey, so the DAO implementation should be injected via the constructor of the service:

@Path("eventscheduler)
public class EventSchedulerService {
    private IEventSchedulerDao dao;

    public EventSchedulerService(IEventSchedulerDao dao) { this.dao = dao; }
}

However, I know Jersey expects a default constructor to setup everything correctly. I have been trying to figure out how to do this for a while but surprisingly this seems to be an uncommon case, I wonder how people inject DAOs into their services, or deal with injection in general at all.

How can I do this?

khelwood
  • 55,782
  • 14
  • 81
  • 108
dabadaba
  • 9,064
  • 21
  • 85
  • 155

2 Answers2

10

If you're using Jersey 2, it uses HK2 as it's DI framework. All resource classes go through the DI lifecycle when they are constructed. And constructor injection is not a problem.

The most basic way (with Jersey) to make an arbitrary object injectable, is to bind in an AbstractBinder

public class Binder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(EventSchedudlerDaoImpl.class).to(EventSchedulerDao.class);
    }
}

Then register the binder with Jersey

public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(new Binder());
    }
}

Then you just need to declare the injection point by adding @Inject on top of the constructor.

@Inject
public EventSchedulerService(EventSchedulerDao dao) {
    this.dao = dao;
}

As far as the binder implementation, the binding syntax basically reads as

bind( Implementation ).to( Contract ).in( Scope );

The bind method can take an instance or it can take a class. When you provide an instance, the Scope is automatically Singleton.

The to method specifies the advertised contract, which is the type that can be declared at the injection point. In this case, only the interface EventSchedulerDao can be used for the injection point. If you don't have an interface you can just do

bindAsContract(EventSchedulerDao.class)

assuming EventSchedulerDao is the implementation class.

The scopes available are PerLookup, RequestScoped and Singleton. If not specified, the default scope will be PerLookup, meaning a new instance of the service will be created for each injection point. You should already know what Singleton means. RequestScoped means that a new instance will be created for each request, which may not be the same as PerLookup, as the service may be injected at multiple points through out the request lifeclyle.

See Also:

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • I might be missing something obvious, but I have done as you specified in your really helpful answer but I am getting multiple exceptions when performing a request: `org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl` seems to be the root one. I created the binder and jersey config classes in separate files. Could this be it? – dabadaba Jun 03 '16 at 11:48
  • Did you already have ResourceConfig before, or are you using web.xml? If you are using web.xml, you might want to look at [this post](http://stackoverflow.com/a/29275727/2587435) – Paul Samsotha Jun 03 '16 at 12:03
  • Yes that was it. However, it seems the DAO is not being injected because I am getting a null pointer exception. Do you have any idea of what could be happening? – dabadaba Jun 03 '16 at 12:10
  • The only thing I can think is you are binding incorrectly. But you are not getting the exception anymore? If you are not getting the exception, it _should_ work. How are you doing your binding? – Paul Samsotha Jun 03 '16 at 12:13
  • The service is being called now. But the dao member in the service is null, so the injection is not working. I am not getting the exeption I was getting before, this one is different. – dabadaba Jun 03 '16 at 12:14
  • Ok, I solved it. I think you should change your answer. Instead of having the inject annotation in the constructor, it should be in the DAO member instead and get rid of the constructor. – dabadaba Jun 03 '16 at 12:15
  • Construction injection should work without a problem. Field injection is also an option. But the constructor injection should work. Dumb question but when using constructor injection, do you initialize the field in the constructor? Personally I prefer construction injection as it's easier to unit test. You should try to get that working. I use it all the time, so I don't know what you are doing differently, why it isn't working for you. – Paul Samsotha Jun 03 '16 at 12:17
  • You're right, I was dumb and removed the assignment line because your original answer omitted it in the constructor. But it works both ways, either annotating the member or annotating the constructor. I guess it's a matter of taste? – dabadaba Jun 03 '16 at 12:21
  • By the way, do you mind if I ask you about something you said in the last block of your answer? Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/113731/discussion-between-dabadaba-and-peeskillet). – dabadaba Jun 03 '16 at 12:21
1

You must annotate the class constructor (or the property itself) with javax.inject.Inject.

import javax.inject.Inject;

class EventSchedulerResource {
  private final IEventSchedulerDao dao;

  @Inject
  public EventSchedulerResource(IEventSchedulerDao dao) {
    this.dao = dao;
  }

  // ...

}

If the IEventScheduler is an interface you must create a configuration class class that extends org.glassfish.jersey.server.ResourceConfig and register the binding of interface to a concrete implementation with bind(EventSchedulerDaoImpl.class).to(IEventScheduler.class) (See here: https://jersey.java.net/documentation/latest/ioc.html chapter 23.1)

Mico
  • 1,978
  • 2
  • 13
  • 17