"PersistService. It was already configured" with multiple Persistence Units

2,621 views
Skip to first unread message

bklough

unread,
Sep 17, 2011, 4:28:55 PM9/17/11
to google...@googlegroups.com
https://groups.google.com/d/msg/google-guice/qYTNDJDoQU4/uHIdJSTqV5MJ

Epic fail so far with various combinations of PrivateModule and expose statements.  Obviously a Spring AOP solution is doable, but... Any insights?  Thoughts?  Contributing info?

Bueller?  Bueller?


scl

unread,
Oct 18, 2011, 7:36:12 AM10/18/11
to google...@googlegroups.com
I faced the same problem.
I found the following solution to register the PersistFilter several times.

you can inject the session provider as follows.

    @Inject @MyDataSourceOne
    private Provider<Session> sessionProvider;


---

@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, PARAMETER, METHOD })
@BindingAnnotation
public @interface MyDataSourceOne {}


@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, PARAMETER, METHOD })
@BindingAnnotation
public @interface MyDataSourceTwo {}


public class MyDataSourceOnePersistModule extends PrivateModule {
    public static final Key<PersistFilter> MY_DATA_SOURCE_ONE_FILTER_KEY = Key.get(PersistFilter.class, MyDataSourceOne.class);

    public void configure() {
        final JpaPersistModule jpm = new JpaPersistModule("myDataSourceOne");
        jpm.properties(new Properties()); // some kinda bug without this
       
        install(jpm);

        bind(Session.class).annotatedWith(MyDataSourceOne.class).toProvider(MyDataSourceOneSessionProvider.class);
        expose(Session.class).annotatedWith(MyDataSourceOne.class);
       
        bind(MY_DATA_SOURCE_ONE_FILTER_KEY).to(PersistFilter.class);
        expose(MY_DATA_SOURCE_ONE_FILTER_KEY);
    }
}


public class MyDataSourceTwoPersistModule extends PrivateModule {
    public static final Key<PersistFilter> MY_DATA_SOURCE_TWO_FILTER_KEY = Key.get(PersistFilter.class, MyDataSourceTwo.class);

    public void configure() {
        final JpaPersistModule jpm = new JpaPersistModule("myDataSourceTwo");
        jpm.properties(new Properties()); // some kinda bug without this
       
        install(jpm);

        bind(Session.class).annotatedWith(MyDataSourceTwo.class).toProvider(MyDataSourceTwoSessionProvider.class);
        expose(Session.class).annotatedWith(MyDataSourceTwo.class);
       
        bind(MY_DATA_SOURCE_TWO_FILTER_KEY).to(PersistFilter.class);
        expose(MY_DATA_SOURCE_TWO_FILTER_KEY);
    }
}


public class WebModule extends ServletModule {

    protected void configureServlets() {
        install(new MyDataSourceOnePersistModule());
        install(new MyDataSourceTwoPersistModule());
       
        // more bindings
       
        filter("/*").through(MyDataSourceOnePersistModule.MY_DATA_SOURCE_ONE_FILTER_KEY);
        filter("/*").through(MyDataSourceTwoPersistModule.MY_DATA_SOURCE_TWO_FILTER_KEY);
    }
   
}

Alexander Lochschmied

unread,
Dec 22, 2011, 9:23:30 AM12/22/11
to google...@googlegroups.com
Can you also share MyDataSourceOneSessionProvider and MyDataSourceTwoSessionProvider?
Thanks!

Alexander Lochschmied

unread,
Dec 23, 2011, 4:15:28 AM12/23/11
to google...@googlegroups.com
That was a good start. But I'm more interested in an EntityManager, so I tried this:

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import com.google.inject.Provider;

public class MyDataSourceOneEntityManagerProvider implements Provider<EntityManager> {
    @Override
    public EntityManager get() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("dsmgmt");
        return emf.createEntityManager();
    }
}

I still get errors:

                00:00:12,785 [WARN] failed guiceFilter
com.google.inject.ConfigurationException: Guice configuration errors:


1) Unable to create binding for javax.persistence.EntityManager. It was already configured on one or more child injectors or private modules
bound at com.google.inject.persist.jpa.JpaPersistModule.configurePersistence(JpaPersistModule.java:71)
If it was in a PrivateModule, did you forget to expose the binding?
while locating com.google.inject.Provider<javax.persistence.EntityManager>
for field at com.vishay.dsmgmt.shared.server.domain.ImageMetaDataService.emp(ImageMetaDataService.java:33)
while locating com.vishay.dsmgmt.shared.server.domain.ImageMetaDataService
for field at com.vishay.dsmgmt.app.tabs.graphics.server.GraphicsUploadServlet.imageMetaDataService(GraphicsUploadServlet.java:62)
while locating com.vishay.dsmgmt.app.tabs.graphics.server.GraphicsUploadServlet

2) Unable to create binding for javax.persistence.EntityManager. It was already configured on one or more child injectors or private modules
bound at com.google.inject.persist.jpa.JpaPersistModule.configurePersistence(JpaPersistModule.java:71)
If it was in a PrivateModule, did you forget to expose the binding?
while locating com.google.inject.Provider<javax.persistence.EntityManager>
for field at com.vishay.dsmgmt.shared.server.domain.UserService.emp(UserService.java:21)
while locating com.vishay.dsmgmt.shared.server.domain.UserService
for field at com.vishay.dsmgmt.app.tabs.graphics.server.GraphicsUploadServlet.userService(GraphicsUploadServlet.java:62)
while locating com.vishay.dsmgmt.app.tabs.graphics.server.GraphicsUploadServlet

2 errors
at com.google.inject.internal.InjectorImpl.getBinding(InjectorImpl.java:150)
at com.google.inject.internal.InjectorImpl.getBinding(InjectorImpl.java:66)
at com.google.inject.servlet.ServletDefinition.init(ServletDefinition.java:103)
at com.google.inject.servlet.ManagedServletPipeline.init(ManagedServletPipeline.java:82)
at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102)
at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:172)
at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:97)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:593)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1220)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload.doStart(JettyLauncher.java:463)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.handler.RequestLogHandler.doStart(RequestLogHandler.java:115)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:222)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at com.google.gwt.dev.shell.jetty.JettyLauncher.start(JettyLauncher.java:667)
at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:500)
at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1055)
at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:804)
at com.google.gwt.dev.DevMode.main(DevMode.java:309)

scl

unread,
Jan 1, 2012, 8:29:54 PM1/1/12
to google-guice
If you want to expose the EntityManager you can do this as follows:

// in your private module:
final Provider<EntityManager> entityManagerProvider =
binder().getProvider(EntityManager.class);
bind(EntityManager.class).annotatedWith(MyDataSourceOne.class).toProvider(entityManagerProvider);
expose(EntityManager.class).annotatedWith(MyDataSourceOne.class);

Now the EntityManager is available outsied the private module:

@Inject @MyDataSourceOne
EntityManager entityManager;


And here is the code to the session provider you asked for:

public class SessionProvider implements Provider<Session> {
/** The entity manger to retrieve the session from. */
@Inject
private Provider<EntityManager> entityManagerProvider;

/**
* @return the Hibernate session, being the delegate of the entity
manager provided by the injected entity manager provider.
*/
@Override
public Session get() {
final Session session = (Session)
entityManagerProvider.get().getDelegate();
// configure session i.e. flush mode or filtering
return session;
}

Alexander Lochschmied

unread,
Mar 7, 2012, 8:36:01 AM3/7/12
to google...@googlegroups.com
Thanks again but I still have problems. Before getting this to work in a servlet (GWT-P dispatch handler), I am trying to run it inside a simple main(). I'm getting the following error when running the code below. It's compaining when invoking the ApplicationInitializer

Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:

1) Unable to create binding for com.google.inject.persist.PersistService. It was already configured on one or more child injectors or private modules
    bound at com.google.inject.persist.jpa.JpaPersistModule.configurePersistence(JpaPersistModule.java:69)
  If it was in a PrivateModule, did you forget to expose the binding?
  while locating com.google.inject.persist.PersistService
    for parameter 0 at SomeService // this line: @Inject ApplicationInitializer(PersistService service) {
  while locating SomeService$ApplicationInitializer

1 error
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
at SomeService // this line: injector.getInstance(ApplicationInitializer.class);
...

public class SomeService {
    @Inject @MyDataSourceOne EntityManager em;
    // ... 

    public static void main(String[] args) {
        Module one = new PrivateModule() {
            protected void configure() {
                final JpaPersistModule jpm = new JpaPersistModule("pu-name");
                jpm.properties(new Properties());
                install(jpm);
                final Provider<EntityManager> entityManagerProvider = 
                        binder().getProvider(EntityManager.class); 
                bind(EntityManager.class).annotatedWith(MyDataSourceOne.class).toProvider(entityManagerProvider);
                expose(EntityManager.class).annotatedWith(MyDataSourceOne.class);
            }
        };
        // similar code for "two"

        Injector injector = Guice.createInjector(one, two);
        injector.getInstance(ApplicationInitializer.class);

        SomeService service = injector.getInstance(SomeService.class);

        // run one of this service's methods
    }

    static class ApplicationInitializer {
        @Inject ApplicationInitializer(PersistService service) {
            service.start();
        }
    }
}

If I do not use ApplicationInitilizer, I'm getting a NullPointerException:

Exception in thread "main" com.google.inject.ProvisionException: Guice provision errors:

1) Error in custom provider, java.lang.NullPointerException
  while locating com.google.inject.persist.jpa.JpaPersistService
  while locating javax.persistence.EntityManager
  at SomeService // this line: bind(EntityManager.class).annotatedWith(MyDataSourceOne.class).toProvider(entityManagerProvider);
  while locating javax.persistence.EntityManager annotated with @....MyDataSourceOne()
    for field at SomeService...
  while locating SomeService

1 error
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:987)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
at SomeService // this line: SomeService service = injector.getInstance(SomeService.class);
Caused by: java.lang.NullPointerException
at com.google.inject.persist.jpa.JpaPersistService.begin(JpaPersistService.java:70)

scl

unread,
Mar 7, 2012, 9:08:40 AM3/7/12
to google...@googlegroups.com
You only exposed the EntityManager in your private module one.
Therefore you can only have the EntityManager injected outside of your private module.

If you want to inject the PersistService you would have to expose it (with annotation).
Reply all
Reply to author
Forward
0 new messages