Question

Im trying to configure hibernatebundle with guice/dropwizard and need help. Im using hubspot / dropwizard-guice / 0.7.0 3rd party library in addition to dropwizard lib.

The code below obviously wont work and need help on figuring it out. How do I rewrite this so that hibernatebundle and ultimately, session factory, be auto injected to whatever bean that needs it.

MyApplication.java

public class MyApplication extends Application<MyAppConfiguration> {

    private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
        @Override
        public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
            return configuration.getDataSourceFactory();
        }
    };

    @Override
    public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
        bootstrap.addBundle(hibernateBundle);  // ???

        bootstrap.addBundle(
            GuiceBundle.<MyAppConfiguration>newBuilder()
                    .addModule(new MyAppModule())
                    .enableAutoConfig(getClass().getPackage().getName())
                    .setConfigClass(MyAppConfiguration.class)
                    .build()
        );
    }

}   

MyAppModule.java

public class MyAppModule extends AbstractModule {

    @Provides
    public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
            // really wrong as it creates new instance everytime.
        return configuration.getHibernateBundle().getSessionFactory(); // ???
    }

}

MyAppConfiguration.java

public class MyAppConfiguration extends Configuration {
    @Valid
    @NotNull
    private DataSourceFactory database = new DataSourceFactory();

    @JsonProperty("database")
    public DataSourceFactory getDataSourceFactory() {
        return database;
    }

    @JsonProperty("database")
    public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
        this.database = dataSourceFactory;
    }

        // ???
    public HibernateBundle<MyAppConfiguration> getHibernateBundle() {
        return new HibernateBundle<MyAppConfiguration>(MyModel.class) {
            @Override
            public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
                return database;
            }
        };
    }

}  
Was it helpful?

Solution

Here is how I end up doing. I never got an answer from here or mailing list so I would consider this hackish and probably not the proper way to do it but it works for me.

In my module (that extends abstractmodule) :

private final HibernateBundle<MyConfiguration> hibernateBundle =
        new HibernateBundle<MyConfiguration>(MyModel.class) {
            @Override
            public DataSourceFactory getDataSourceFactory(MyConfiguration configuration) {
                return configuration.getDataSourceFactory();
            }
        };

@Provides
public SessionFactory provideSessionFactory(MyConfiguration configuration,
                                            Environment environment) {

    SessionFactory sf = hibernateBundle.getSessionFactory();
    if (sf == null) {
        try {
            hibernateBundle.run(configuration, environment);
        } catch (Exception e) {
            logger.error("Unable to run hibernatebundle");
        }
    }

    return hibernateBundle.getSessionFactory();
}

revised:

public SessionFactory provideSessionFactory(MyConfiguration configuration,
                                            Environment environment) {

    SessionFactory sf = hibernateBundle.getSessionFactory();
    if (sf == null) {
        try {
            hibernateBundle.run(configuration, environment);
            return hibernateBundle.getSessionFactory();
        } catch (Exception e) {
            logger.error("Unable to run hibernatebundle");
        }
    } else {
        return sf;
    }
}

OTHER TIPS

I thought the explicit run(configuration, environment) call (in the answer provided by @StephenNYC) was a bit weird so a digged a little deeper. I found out that AutoConfig in dropwizard-guice wasn't setting up ConfiguredBundle's correctly (HibernateBundle is such a type).

As of https://github.com/HubSpot/dropwizard-guice/pull/35 the code can now look like this instead:

@Singleton
public class MyHibernateBundle extends HibernateBundle<NoxboxConfiguration> implements ConfiguredBundle<MyConfiguration>
{
    public MyHibernateBundle()
    {
        super(myDbEntities(), new SessionFactoryFactory());
    }

    private static ImmutableList<Class<?>> myDbEntities()
    {
        Reflections reflections = new Reflections("com.acme");
        ImmutableList<Class<?>> entities = ImmutableList.copyOf(reflections.getTypesAnnotatedWith(Entity.class));
        return entities;
    }

    @Override
    public DataSourceFactory getDataSourceFactory(NoxboxConfiguration configuration)
    {
        return configuration.getMyDb();
    }
}

@Provides
public SessionFactory sessionFactory(MyHibernateBundle hibernate)
{
    return checkNotNull(hibernate.getSessionFactory());
}

The magic behind this is that MyHibernateBundle implements ConfiguredBundle which dropwizard-guice now automatically picks up and instantiates.

Here is the way I solved it :
Put the Hibernate bundle in the guice module and pass the bootstap object as argument of guice module constructor so the hibernate bundle can be added to it.
The configuration can remain exactly as you would use a hibernate-bundle without guice.
I got this working with dropwizard-hibernate v0.7.1 and dropwizard-guice v0.7.0.3

MyAppModule.java :

public class MyAppModule extends AbstractModule {
  private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
    @Override
    public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
        return configuration.getDataSourceFactory();
    }
  };

  public MyAppModule(Bootstrap<MyAppConfiguration> bootstrap) {
    bootstrap.addBundle(hibernateBundle);
  }

  @Override
  protected void configure() {
  }

  @Provides
  public SessionFactory provideSessionFactory() {
    return hibernateBundle.getSessionFactory();
  }
}

MyApplication.java :

public class MyApplication extends Application<MyAppConfiguration> {

  @Override
  public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
    bootstrap.addBundle(
            GuiceBundle.<MyAppConfiguration>newBuilder()
                    .addModule(new MyAppModule(bootstrap))
                    .enableAutoConfig(getClass().getPackage().getName())
                    .setConfigClass(MyAppConfiguration.class)
                    .build()
    );
  }

  @Override
  public void run(final MyAppConfiguration configuration, final Environment environment) throws Exception {
  }

}  

MyAppConfiguration.java :

public class MyAppConfiguration extends Configuration {
  @Valid
  @NotNull
  @JsonProperty("database")
  private DataSourceFactory database = new DataSourceFactory();

  public DataSourceFactory getDataSourceFactory() {
    return database;
  }
}

I have not used hibernate in dropwizard, but I have used Guice and you really only need to worry about MyAppModule. That's where the magic will happen:

public class MyAppModule extends AbstractModule {

    @Singleton
    @Provides
    public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
        HibernateBundle<MyAppConfiguration> hibernate = new HibernateBundle<ExampleConfiguration>(MyModel.class) {
            @Override
            public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
                return configuration.getDataSourceFactory();
            }
        }

        return hibernate.getSessionFactory();
    }
}

(see here for multiple Classes)

MyAppConfiguration.java and MyApplication.java should not have any of the hibernate bundle references in. You should then be able to @Inject a SessionFactory where ever you need it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top