Dropwizard and Guice: Injection Medium

I am currently creating a Dropwizard + Guice + Jersey application where database access is currently being processed by JDBI.

What I'm trying to achieve is to have a typical corporate architecture, where resources access classes of service that access the DAO class, which in turn accesses the database. It would be nice to get all this in the correct DI order, although I think I can build my object graph in the run () method of the application if all else fails.

So, I ran into this problem, which was mentioned here before : Getting DBIFactory requires both an environment and a configuration that somehow needs to be available at the time that Guice is doing magic for injection, and not at runtime () time .

Being Dropwizard and Guice noob, I managed to collect so far that I need a provider for my DAO objects, something like a melody

public class UserDAOProvider implements Provider<UserDAO> { @Inject Environment environment; @Inject Configuration configuration; @Override public UserDAO get() { final DBIFactory factory = new DBIFactory(); final (MyConfiguration) config = (MyConfiguration) configuration; DBI jdbi = null; try { jdbi = factory.build(environment, config.getDataSourceFactory(), "mysql"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return jdbi.onDemand(UserDAO.class); } } 

By registering this as a singleton provider, I must then enter UserDAO into my services.

Now, how do we actually get the environment embedded in the Provider? I am currently stuck in Guice complaining that I did not find a suitable constructor for the environment, so it is trying to create an instance and not grab it from Dropwizard itself.

This seems to be doable; There is a dropwizard-guice package, DropWizardEnvironmentModule, I think I need. But I feel like I just missed some piece of the puzzle here to figure out how to stack things. So far I have not been able to find a complete working example ...

+6
source share
3 answers

I had the same problem as the OP, but using Hibernate, not JDBI. My simple solution applies to JDBI, however - just switch DBIFactory to SessionFactory .

First add the injection provider for singleton SessionFactory to your Guice module:

 public class MyModule extends AbstractModule { private SessionFactory sessionFactory; @Override protected void configure() { } @Provides SessionFactory providesSessionFactory() { if (sessionFactory == null) { throw new ProvisionException("The Hibernate session factory has not yet been set. This is likely caused by forgetting to call setSessionFactory during Application.run()"); } return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } } 

You need to install singleton SessionFactory from the run () method of your application. In your case, using JDBI, you must create and configure your DBIFactory before passing it to the Guice module:

 public void run(MyConfiguration configuration, Environment environment) { myModule.setSessionFactory(hibernateBundle.getSessionFactory()); ... } 

SessionFactory can now be entered wherever needed. Now I use implicit binding for my DAO classes, just annotating the constructor with @Inject and introducing a Singleton SessionFactory. I explicitly do not create providers for DAO classes:

 @Singleton public class WidgetDAO extends AbstractDAO<App> { @Inject public WidgetDAO(SessionFactory factory) { super(factory); } public Optional<Widget> findById(Long id) { return Optional.fromNullable(get(id)); } ... } 

Now I can embed my singleton DAO instances in resources:

 @Path("/widgets") @Produces(MediaType.APPLICATION_JSON) public class WidgetsResource { private final WidgetDAO widgetDAO; @Inject public WidgetsResource(WidgetDAO widgetDAO) { this.widgetDAO = widgetDAO; } ... } 

Note that this approach follows Guice guidelines for direct dependency injection. Do not try to enter Envrionment and Configuration just so that you can create a DBI factory - insert the previously created DBI factory itself.

+4
source

This is how I use Guice with Dropwizard. Inside your run () method add a line

 Guice.createInjector(new ConsoleModule()); 

You cannot enter Environ

Create a ConsoleModule Class

 public class ConsoleModule extends AbstractModule { //configuration and env variable declaration public ConsoleModule(ConsoleConfiguration consoleConfig, Environment env) { this.consoleConfig = consoleConfig; this.env= env; } protected void configure() { //You should not inject Configuration and Environment in your provider since you are mixing //dropwizard framework stuff with Guice.Neverthless you will have to bind them in the below order bind(Configuration.class).toInstance(consoleConfig.class); bind(Environment.class).toInstance(env.class); bind(UserDAO.class).toProvider(UserDAOProvider.class).in(Singleton.class); } } 
+3
source

We have the same configuration (dw-jdbi-guice), as well as the abstract base class Application , which further complicates the situation.

Since many things happen during the run method, and many things depend on configuration objects, we have finished creating the injector in the run method. But since we also need objects from bootsrap (for example, ObjectMapper), we get the List<Module> field in the Application class. Not the most pleasant solution, but can work with various scenarios.

0
source

Source: https://habr.com/ru/post/974583/


All Articles