Problème avec GUICE + JPA
Bonjour,
Je suis en train d'intégrer JPA (utilisation d'eclipselink comme provider) à mon application web. Mon application s'appuie sur la solution GWT + GIN + GUICE. Et j'essaie donc d'intégrer JPA par le biais de Guice-Persist. Pour faire cela, je me suis appuyé sur la doc de Guice (http://code.google.com/p/google-guice/wiki/JPA).
Lors du lancement de l'application, j'obtiens l'exception suivante :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| sept. 19, 2012 5:30:09 PM com.google.apphosting.utils.jetty.JettyLogger info
Infos: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
sept. 19, 2012 5:30:09 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
Infos: Successfully processed /home/nicolas/workspace/java/Aquamoni/war/WEB-INF/appengine-web.xml
sept. 19, 2012 5:30:09 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
Infos: Successfully processed /home/nicolas/workspace/java/Aquamoni/war/WEB-INF/web.xml
sept. 19, 2012 5:30:13 PM com.google.apphosting.utils.jetty.JettyLogger warn
Avertissement: Failed startup of context com.google.appengine.tools.development.DevAppEngineWebAppContext@5abc5c2c{/,/home/nicolas/workspace/java/Aquamoni/war}
com.google.inject.ProvisionException: Guice provision errors:
1) Error injecting constructor, java.lang.NullPointerException
at com.aquamoni.webmonitor.server.injection.PersistenceInitializer.<init>(PersistenceInitializer.java:9)
at com.aquamoni.webmonitor.server.injection.PersistenceInitializer.class(PersistenceInitializer.java:9)
while locating com.aquamoni.webmonitor.server.injection.PersistenceInitializer
1 error
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:987)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
at com.aquamoni.webmonitor.server.injection.GuiceServletConfig.getInjector(GuiceServletConfig.java:25)
at com.google.inject.servlet.GuiceServletContextListener.contextInitialized(GuiceServletContextListener.java:45)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:197)
at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:241)
at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:148)
at com.google.appengine.tools.development.gwt.AppEngineLauncher.start(AppEngineLauncher.java:97)
at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:509)
at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1068)
at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:811)
at com.google.gwt.dev.DevMode.main(DevMode.java:311)
Caused by: java.lang.NullPointerException
at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:330)
at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
at com.google.inject.persist.jpa.JpaPersistService.start(JpaPersistService.java:94)
at com.aquamoni.webmonitor.server.injection.PersistenceInitializer.<init>(PersistenceInitializer.java:10)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(Runtime.java:127)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Runtime.java:135)
at com.google.inject.internal.DefaultConstructionProxyFactory$2.newInstance(DefaultConstructionProxyFactory.java:85)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:85)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1031)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.Scopes$1$1.get(Scopes.java:65)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40)
at com.google.inject.internal.InjectorImpl$4$1.call(InjectorImpl.java:978)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1024)
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:974)
... 22 more |
Voici la vue Explorer d'Eclipse qui permettra de voir comment mon projet est structuré :
http://imageshack.us/a/img32/937/strucuture.png
J'ai donc ma classe GuiceServletConfig avec une classe Binder et une classe Mapping :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
Injector injector = Guice.createInjector(new AbstractModule[]{
// register the service binder
new ServicesBinder(),
// register db persistence
new JpaPersistModule("aquamoni"),
// register the url mapping
new ServletMapping()
});
injector.getInstance(PersistenceInitializer.class);
return injector;
}
} |
Code:
1 2 3 4 5 6 7 8 9 10
| public class ServicesBinder extends AbstractModule {
protected void configure() {
bind(TemperaturesService.Iface.class).to(TemperaturesServiceImpl.class).in(Scopes.SINGLETON);
bind(AquariumDAO.class);
}
} |
Code:
1 2 3 4 5 6 7 8 9
| public class ServletMapping extends ServletModule {
@Override
protected void configureServlets() {
serve("/aquamoni/Temperatures").with(TemperaturesServiceImpl.class);
}
} |
PersistenceInitializer, une classe permettant de démarrer service de persistence :
Code:
1 2 3 4 5 6 7 8
| @Singleton
public class PersistenceInitializer {
@Inject PersistenceInitializer(PersistService service) {
service.start();
// At this point JPA is started and ready.
}
} |
Mon fichier persistence.xml situé dans src/META-INF/
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="aquamoni" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- JPA entities must be registered here -->
<class>com.aquamoni.webmonitor.server.dao.entities.Aquarium</class>
<properties>
<property name="javax.persistence.jdbc.password" value="" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/aquamoni" />
</properties>
</persistence-unit>
</persistence> |
Voici la liste des JARs dans WEB-INF/lib
http://imageshack.us/a/img850/5838/jars.png
En mode Debug, je me suis rendu compte que l'exception était catché dans la classe PersistenceInitializer au moment service.start().
En effet, les propriétés de service sont null et l'objet service n'a pas les paramètres de connexion à la base de données. J'ai donc pensé au fichier persistence.xml qui n'est pas chargé. Mais, je me suis rendu compte que quand le fichier persistence n'est pas présent, un warning apparait des les logs d'erreurs.
J'ai aussi testé la solution GUICE + JPA dans une application J2SE et ça fonctionne correctement. Il semblerait qu'il y ait une configuration particulière à faire pour les applications J2EE.
Si quelqu'un a une idée d'où vient mon problème, n'hésitez pas à m'en faire part.