im pretty new in working with dropwizard. Currently I'm trying to implement the HK2 dependency injection. That works pretty fine inside a resource but it doesn't work outside of a resource. Here is what I'm doing:
Client client = new JerseyClientBuilder(environment).using(configuration.getJerseyClientConfiguration()).build("contentmoduleservice");
//DAOs
ContentModuleDAO contentModuleDAO = new ContentModuleDAO(hibernate.getSessionFactory());
ModuleServedDAO moduleServedDAO = new ModuleServedDAO(hibernate.getSessionFactory());
//Manager
ContentModuleManager moduleManager = new ContentModuleManager();
EntityTagManager eTagManager = new EntityTagManager();
ProposalManager proposalManager = new ProposalManager(client, configuration);
environment.jersey().register(new AbstractBinder() {
#Override
protected void configure() {
bind(eTagManager).to(EntityTagManager.class);
bind(contentModuleDAO).to(ContentModuleDAO.class);
bind(moduleServedDAO).to(ModuleServedDAO.class);
bind(proposalManager).to(ProposalManager.class);
bind(moduleManager).to(ContentModuleManager.class);
}
});
I create Instance of the classes I want to be injectible and bind them.
Inside my resource the injection works:
#Api
#Path("/api/contentmodule")
public class ContentModuleResource {
static final Logger LOG = LoggerFactory.getLogger(ContentModuleResource.class);
static final int MAX_PROPOSALS_PER_MODULE = 10;
#Inject
private ContentModuleDAO contentModuleDAO;
#Inject
private EntityTagManager eTagManager;
#Inject
private ProposalManager proposalManager;
#Inject
private ContentModuleManager contentModuleManager;
All these variables are filled with an Instance of the right class.
The problem is: The ContentModuleManager should also get some of these classes via injection:
public class ContentModuleManager {
#Inject
private ContentModuleDAO contentModuleDAO;
#Inject
private ProposalManager proposalManager;
#Inject
private ModuleServedDAO moduleServedDAO;
But those are null. Can somebody explain a dropwizard noob why this happens and how I can fix this? :D
Thanks!
If you are going to instantiate the service yourself then it is not going to go through the DI lifecycle and will never be injected. You can let the container create the service if you just register the services as a class
bind(ContentModuleManager.class)
.to(ContentModuleManager.class)
.in(Singleton.class);
On the other hand, if you are creating all the services yourself and you have all of them available, why don't you just not use the DI container at all? Just pass all the services through the constructor. Whether you are using constructor injection1 or manually passing through the constructor, getting the service through the constructor is good practice anyway, as it allows for easier testing of the service.
1 - Constructor injection
private Service service;
#Inject
public OtherService(Service service) {
this.service = service;
}
Related
I have a large existing java program already using Guice. I'm trying to add an embedded website with swagger documentation. Somehow I need to wire it all up with Guice, but everything I've tried throws null pointer exception when I try to use things I injected in my main program. I thought maybe I could pass the injector and wire it up that way, either using the injector or creating a child injector.
I've created a sample app using just the code needed to get this working, with a URL that works but doesn't try to grab use the injections from my main program, and one that does not work that tries to use the injection.
I'm trying to do all this without needing the web.xml via:
private ContextHandler buildApiContext() {
ResourceConfig resourceConfig = new ResourceConfig();
// Replace EntityBrowser with your resource class
// io.swagger.jaxrs.listing loads up Swagger resources
resourceConfig.packages("web", ApiListingResource.class.getPackage().getName());
//apiServletContainer.reload(resourceConfig);
ServletContainer apiServletContainer = new ServletContainer(resourceConfig);
final ServletContextHandler apiContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
apiContext.setContextPath("/api");
ServletHolder apiBrowser = new ServletHolder(apiServletContainer);
apiContext.addFilter(GuiceFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
myGuiceServletContextListener.setMainInjector(blackboard.getMainInjector());
apiContext.addEventListener(myGuiceServletContextListener);
apiContext.addServlet(apiBrowser, "/*");
return apiContext;
}
and
public class MyGuiceServletContextListener extends GuiceServletContextListener {
#Inject private Blackboard blackboard;
#Override
protected Injector getInjector() {
return blackboard.getMainInjector();
}}
I also tried:
return blackboard.getMainInjector().createChildInjector();
In my main I'm starting the main program injection with:
Config config = ReadConfig.createConfig();
Injector injector = Guice.createInjector(new Bindings(config));
BigProgramInterface bbInterface = injector.getInstance(BigProgramImpl.class);
bbInterface.start(injector);
where Bindings looks like
public class Bindings implements Module {
private Config config;
public Bindings(Config config) {
this.config = config;
}
public void configure(Binder binder) {
Integer fixedThreadPoolSize = 2;
Executor fixedExecutor = Executors.newFixedThreadPool(fixedThreadPoolSize, new FixedThreadFactory());
binder.bind(Executor.class).toInstance(fixedExecutor);
binder.bind(Config.class).toInstance(config);
binder.bind(Blackboard.class).asEagerSingleton();
binder.bind(BigProgramMain.class).asEagerSingleton();
binder.bind(EmbeddedWeb.class).asEagerSingleton();
//binder.bind(MyGuiceServletContextListener.class).asEagerSingleton();
}
The blackboard is injected, and it is getting the main injector, but it can't use it.
works:
#Path("/test")
#Api (value = "/test")
public class TestSwagger {
private static final Logger log = LoggerFactory.getLogger(TestSwagger.class);
#GET
#Path("/get")
#ApiOperation(value = "a working test",
notes = "Returns my test class",
response = MyTest.class,
responseContainer="Class")
#Produces(MediaType.APPLICATION_JSON)
public Response getResult() {
MyTest myTest = new MyTest();
myTest.setMyTestString("this is a test");
return Response.ok().entity(myTest).build();
}}
not working:
#Path("/testbad")
#Api (value = "/testbad")
public class TestSwaggerBad {
private static final Logger log = LoggerFactory.getLogger(TestSwaggerBad.class);
#Inject private Blackboard blackboard;
#GET
#Path("/get")
#ApiOperation(value = "a non - working test",
notes = "Returns my test class",
response = MyTest.class,
responseContainer="Class")
#Produces(MediaType.APPLICATION_JSON)
public Response getResult() {
MyTest myTest = new MyTest();
myTest.setMyTestString(blackboard.getBigProgramCounter().toString());
return Response.ok().entity(myTest).build();
}}
Please see my code for the nitty gritty details:
https://github.com/phomlish/SwaggerSampleApiWebsite
I had a closer look at your code, here is how you get it to work:
Add the guice bridge to your pom:
<!-- https://mvnrepository.com/artifact/org.glassfish.hk2/guice-bridge -->
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>guice-bridge</artifactId>
<version>2.5.0-b15</version>
</dependency>
That adds the guice hk2 bridge to your configuration. Now, you will want to wire that up. For that, we will create a feature as outlined by this post:
Guice don't inject to Jersey's resources
#Priority(0)
public class GuiceFeature implements Feature {
private Injector i;
public GuiceFeature(Injector i) {
this.i = i;
}
#Override
public boolean configure(FeatureContext context) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(i);
return true;
}
}
Note that I am passing the injector that you created into that feature. This is important since you will need that same injector in order to be able to find your service. The binding code is fairly straight forward.
Finally, you will need to register that feature. In your class EmbeddedWeb, you add:
EmbeddedWeb#buildApiContext:
resourceConfig.register(new GuiceFeature(myGuiceServletContextListener.getInjector()));
Again, we are using the same injector that you created already.
Finally that is all that you need and your services are wired up correctly.
test:
artur#pandaadb:~/dev/repo/SwaggerSampleApiWebsite$ curl "http://localhost:8080/api/testbad/get"
{"myTestString":"10"}
Hope that helps,
artur
EDIT '''IMPORTANT''':
For injection, you can not use guice annotations. Jersey doesn't seem to recognise them (likely because they did not want to add guice dependencies). Luckily, guice can work with both javax and guice annotations. So in your TestSwaggerBad class you will also need to change the import to standard javax annotations.
I'm using Guice in a Restlet web server, and there's one pattern I can't figure out: how to inject objects that are specific to a certain user or a certain request.
Say we have a request to list all the Widgets that belong to a project. The service that looks up Widgets requires a Project instance. There are many Projects in the system.
My code currently looks something like this:
public class WidgetResource extends ServerResource {
//path: project/{project}/widgets
private final WidgetService service;
private final ProjectLookup projectLookup;
#Inject
public WidgetResource(WidgetService service, ProjectLookup projectLookup) {
this.service = service;
this.projectLookup = projectLookup;
}
#Get
public WidgetCollection getWidgets() {
String projectName = getAttribute("project"); //restlet lookup of path var
Project project = projectLookup.get(projectName);
WidgetCollection widgets = service.getWidgetsFor(project);
return widgets;
}
}
This works well enough, but it's clumsy, and I hope there's a better way. It would be great to inject the correct Project object directly. Is there a way to do this?
So far I've explored AssistedInject, which gives a factory object very similar to my Lookup. I came close to an answer with custom annotations/injections, but dead-ended because the Restlet attributes map isn't populated until after injection. Have read the GitHub docs and the User's Guide. Can't spot anything.
I'd like to end up with something like this:
public class WidgetResource extends ServerResource {
private final WidgetService service;
#Inject
public WidgetResource(WidgetService service) {
this.service = service;
}
#Inject
#Get
public WidgetCollection getWidgets(#PathName("project") Project project) {
WidgetCollection widgets = service.getWidgetsFor(project);
return widgets;
}
with (of course) a #Provides method in the configuration that would look up the path variable and use the lookup. However, I can't figure out a way to hand a provider method the path name or the Resource instance as variables. Is this possible? Any help appreciated!
To your vision: You can not inject into "getWidgets" ... injection happens the very moment your widgetResource is created, so basically once your application/server starts.
Besides that, it looks perfectly fine. You have a REST resource that takes a project parameter and uses a service to look up widgets.
If you know all possible project names in advance, you could use guice' mapBinder instead of the service.
public class WidgetsModule extends AbstractModule {
protected void configure() {
MapBinder<String, WidgetCollection> mapbinder
= MapBinder.newMapBinder(binder(), String.class, WidgetCollection.class);
mapbinder.addBinding("project1").toInstance(...);
mapbinder.addBinding("project2").toProvider(...);
mapbinder.addBinding("project3").to(...);
}
}
i'm new to spring, and i have a question that i couldn't find an answer for it -
during a method execution, i need to create new instances of a managed bean (scope == prototype) in a pre-defined quantity:
#Component
class SomeClass
{
#Resource
private ConnectionFactory conFactory;
private Set <Client> clients;
#Value ("${clientsNum}")
private int clientsNum;
public void init ()
{
Client client = null; //an interface, that the managed bean implements.
for (int i = 0; i < clientsNum; i++)
{
client = ... //how to get a new client instance?
clients.add (client);
client.doSomething ();
}
}
public void shutdown ()
{
for (Client client : clients)
client.shutdown ();
conFactory.shutdown ();
}
}
how do i do that?
i know i can use the init-method \ #PostConstruct annotation (and the matching destroy method), but i don't know how to get the instances according to the required amount.
i searched for the issue in the past few days, and read about service locator, lookup method and factory bean. they all use CGLIB (which i prefer NOT to use) or spring's ApplicationContext (which creates a dependency in spring's implementation), and above all - they don't handle the creation of beans during a method invocation (or at least - i didn't understand how to use them during the invocation).
please assist.
thanks.
EDIT:
eventually i realized that i have to use either CGLIB or Spring's application context, and i chose to use the service locator option.
I'm afraid you have to use CGLIB or ApplicationContext since you wanted a managed bean.
Lookup method injection
Add a lookup method to your SomeClass:
#Lookup
private Client createClient() {
return null; // Never mind, this method will be overridden
}
Then in init(), you can just call it:
client = createClient();
Note that #Lookup annotation was introduced in Spring 4.1.0. You need XML config if you're using older versions.
Using ApplicationContext
Declare an auto wired property:
#Autowired
private ApplicationContext applicationContext;
And in init():
client = applicationContext.getBean(Client.class);
I guess some type of factory would be a better choice for you, you may define a factory method which takes clientsNum as parameter and returns a set to you. This way you can hide all the details from your service class.
If you still want to do this using dependency injection you can try method injection. Have a look at following code to get an idea.
#Component
class SomeClass
{
#Resource
private ConnectionFactory conFactory;
protected abstract Client createClient();
private Set <Client> clients;
#Value ("${clientsNum}")
private int clientsNum;
public void init ()
{
Client client = null; //an interface, that the managed bean implements.
for (int i = 0; i < clientsNum; i++)
{
client = createClient();
clients.add (client);
client.doSomething ();
}
}
public void shutdown ()
{
for (Client client : clients)
client.shutdown ();
conFactory.shutdown ();
}
}
You can find a complete example for method injection with simple google search. But i recommend going with the first solution, its more clean.
i don't know how to get a new instance of the managed bean, without using injection, but during a method invocation.
Inject the Spring ApplicationContextand then use ApplicationContext.getBean(...)
#Autowired
private ApplicationContext applicationContext;
public void init ()
{
Client client = null; //an interface, that the managed bean implements.
for (int i = 0; i < clientsNum; i++)
{
/*>>>>*/ client = applicationContext.getBean(Client.class);
clients.add (client);
client.doSomething ();
}
}
I need a suggestion for how to code for multiple implementations for a service using Google-guice. Below is the example
TestService testService =new TestServiceImplOne();
TestService testService =new TestServiceImplTwo();
As Guice doesn't allow binding a type to more than one implementations as the below code results in error
binderObject.bind(SomeType.class).to(ImplemenationOne.class);
binderObject.bind(SomeType.class).to(ImplemenationTwo.class);
we can solve this with named annotations as below
binder.bind(Player.class).annotatedWith(Names.named("Good")).to(GoodPlayer.class);
binder.bind(Player.class).annotatedWith(Names.named("Bad")).to(BadPlayer.class);
#Named("Good") Player goodPlayer = (Player)injector.getInstance(Player.class);
#Named("Bad") Player badPlayer = (Player)injector.getInstance(Player.class);
But the application which iam working is something like this. We are binding all the modules in the init() method and creating the injector modules:
//separate method to bind
protected void configure() {
bind(new TypeLiteral<List<Service>>() {}).toInstance(serviceSets);
}
//separate method to inject
Injector i = Guice.createInjector(modules);
But with the above process I can just bind one implementation class to the interface (service class)
Could you please provide me a way to do this with providers. I would like to do something like this below
class TestServiceProvider extends Provider{
// some code where it returns the instance of impl class needed. In my case TestServiceImplOne and TestServiceImplTwo and provider returns the corresponding instance of service class
}
and bind service class with provider class. Something like this
bind(TestService.class).toProvider(TestServiceProvider.class);
I would appreciate if someone suggests a good example using providers or some other way that I can inject whatever implementation I want in the client.
Note: I am using webservices and I am not sure how I can inject different implementations when a webservice is called to a service class.
First of all thanks very much for responding . Coming straight to the point
Iam working on webservices . Heres's the Flow
// GET URI
GET http://www.google.com:8182/indi/provide/organizations/{ou}
OrganizationsResource -------->OrganizationService------>OrganizationServiceImpl
Iam binding OrganizationService with OrganizationServiceImpl and injecting the OrganizationService in OrganizationsResource
#Inject
public void setOrganizationService(OrganizationService orgService) {
this.orgService= orgService;
}
Its fine till here but i have two implementations for OrganizationService ------>OrgDeatilsServiceImpl which does some other job
Now i want to bind both OrganizationServiceImpl and OrgDeatilsServiceImpl to OrganizationService
Confusions:
1) What procedure i have to use in Guice to bind two implementaions?
2) How exactly i can code in OrganizationsResource to dynamically decide which implementation to call.
I would appreciate if you give a sample example for the above requirement.
As Vladimir noted, you can use binding annotations with Providers...
// in YourModule.configure():
bind(TestService.class)
.annotatedWith(Names.named("foo")
.toProvider(TestServiceProvider.class);
...and generic types using TypeLiterals...
bind(new TypeLiteral<List<Service>>() {})
.annotatedWith(Names.named("bar")
.toInstance(serviceSets);
...as long as you ask for an annotated instance using getInstance(Key<T>)...
List<Service> servicesOne = injector.getInstance(
new Key<List<Service>>(Names.named("bar")) {});
// or
List<Service> servicesTwo = injector.getInstance(
Key.get(new TypeLiteral<List<Service>>() {}, Names.named("bar"));
...or, preferably, keep them as fields and let Guice do the injecting, because Guice can't inject local variables. Remember that Guice can only inject classes that it creates, or that you request specifically.
class MyInjectorCreator {
#Inject #Named("foo") Provider<TestService> fooServiceProvider;
#Inject #Named("bar") List<Service> barServices;
// Guice will also wrap/unwrap Providers automatically.
#Inject #Named("foo") TestService fooService;
#Inject #Named("bar") Provider<List<Service>> barServicesProvider;
public void createInjector() {
Injector injector = Guice.createInjector(getListOfModules());
injector.injectMembers(this);
}
}
Now, that answers the question as you phrased it in the title. That said, it sounds like you actually want to choose between implementations at runtime, which is a slightly different but easy-to-solve problem:
class TestServiceProvider extends Provider<TestService> {
// Injection is allowed here!
#Inject ApplicationSettings settings;
#Inject Provider<TestServiceImplOne> oneProvider;
#Inject Provider<TestServiceImplTwo> twoProvider;
#Override public TestService get() {
if (settings.isInTestMode()) {
return new TestTestServiceImplImpl(); // without injection!
} else if (settings.useNewService()) {
return twoProvider.get(); // with injection!
} else {
return oneProvider.get(); // also with injection!
}
}
}
But I should warn you that if you know at injector creation time which service to use, you should probably just bind it correctly then for the sake of code cleanliness and ease of readability:
// in YourModule.configure():
if (settings.isInTestMode()) {
bind(TestService.class).toInstance(new TestTestServiceImplImpl());
} else if (settings.useNewService()) {
bind(TestService.class).to(TestServiceImplTwo.class);
} else {
bind(TestService.class).to(TestServiceImplOne.class);
}
I have a class called Drives which dynamically instantiates FsAccess beans.
I have a service class called ServersAccessService which finds FsAccess beans and stores them in a map using #autowired. Is there a way to have the service class initiate the #autowired after Drives is finished instantiating the FsAccess beans?
Service Class:
public class ServersAccessService implements DisposableBean {
protected static final Log log = LogFactory.getLog(ServersAccessService.class);
protected static Map<String, FsAccess> servers = new HashMap<String, FsAccess>();
I
protected Map<String, FsAccess> restrictedServers = new HashMap<String, FsAccess>();
protected boolean isInitialized = false;
protected static Map<String, DrivesCategory> drivesCategories = new HashMap<String, DrivesCategory>();
#Autowired
public void setServers(List<FsAccess> servers) {
for(FsAccess server: servers) {
this.servers.put(server.getDriveName(), server);
}
}
Drives class:
MyBeanFactory mbf = new MyBeanFactory();
//loop through each drive in driveList
for(String name:driveList)
{
String fullUri = "smb://naz-fs3/home/"+name;
String icon = "/esup-portlet-stockage/img/drives/root.png";
VfsAccessImpl drive = mbf.createInstance();
//Set attribute information
drive.setDriveName(name);
drive.setIcon(icon);
drive.setUri(fullUri);
drive.setContextToken(name);
}
If the Drives bean is instantiating the FsAccess beans in it's initialization phase, you may declare the dependency of the ServersAccessService bean via depends-on to the Drives bean. This forces the initialization of the Drives bean before the initialization of the ServersAccessService bean.
I believe what you want is to make your drives class a #Configuration bean, and make the method that returns a List annotated with #Bean. That way the spring container knows about the FsAccess list and it can be available for injection via #Autowired.
EDIT:
Reference: http://blog.springsource.com/2006/11/28/a-java-configuration-option-for-spring/