So I am in the process of migrating a Java8-based app to a Java11-based app. While on Java8, the app was relaying on bundled legacy services (Jersey 2.25) and GAE provided a roadmap for seamlessly moving to Java11 by effecting a few changes in a couple of XML files. I made those changes as per "If your app is using the legacy bundled services, App Engine deploys it using Jetty in the same way as in the Java 8 runtime." here and here.
After having made those changes, I can see Java11 on the GAE console. I do not use any Java11-specific features in my code so I am happy with the Java8 codebase, for now.
However, when the app performs a database I/O on an Entity that has an attribute defined as List<MyCustomType>, I get this exception....
javax.servlet.ServletException: javax.persistence.PersistenceException: Class "com.applix.cliniX.entities.Estb" field "com.applix.cliniX.entities.Estb" : declared as a reference type (interface/Object) but no implementation classes of "java.util.List" have been found!
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:489)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1459)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656)
at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:78)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:571)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at com.google.apphosting.runtime.jetty9.ParseBlobUploadHandler.handle(ParseBlobUploadHandler.java:125)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
at com.google.apphosting.runtime.jetty9.AppEngineWebAppContext.doHandle(AppEngineWebAppContext.java:289)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at com.google.apphosting.runtime.jetty9.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:113)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.SizeLimitHandler.handle(SizeLimitHandler.java:96)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
at com.google.apphosting.runtime.jetty9.RpcConnection.handle(RpcConnection.java:269)
at com.google.apphosting.runtime.jetty9.RpcConnector.serviceRequest(RpcConnector.java:100)
at com.google.apphosting.runtime.jetty9.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:184)
at com.google.apphosting.runtime.RequestRunner.dispatchServletRequest(RequestRunner.java:262)
at com.google.apphosting.runtime.RequestRunner.dispatchRequest(RequestRunner.java:227)
at com.google.apphosting.runtime.RequestRunner.run(RequestRunner.java:193)
at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:273)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: javax.persistence.PersistenceException: Class "com.applix.cliniX.entities.Estb" field "com.applix.cliniX.entities.Estb" : declared as a reference type (interface/Object) but no implementation classes of "java.util.List" have been found!
at org.datanucleus.api.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:302)
at org.datanucleus.api.jpa.JPAQuery.getSingleResult(JPAQuery.java:253)
at com.applix.cliniX.serverApp.dao.DaoEstb.getEstbByName(DaoEstb.java:1096)
at com.applix.cliniX.serverApp.controller.StartupController.getLatestVersionDeployDate(StartupController.java:290)
at com.applix.cliniX.serverApp.controller.StartupController.newVersionDeployed(StartupController.java:304)
at com.applix.cliniX.serverApp.controller.StartupController.loadCache(StartupController.java:207)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
... 45 more
Caused by: org.datanucleus.metadata.InvalidMemberMetaDataException: Class "com.applix.cliniX.entities.Estb" field "com.applix.cliniX.entities.Estb" : declared as a reference type (interface/Object) but no implementation classes of "java.util.List" have been found!
at org.datanucleus.metadata.MetaDataUtils.getImplementationNamesForReferenceField(MetaDataUtils.java:549)
at org.datanucleus.store.mapped.mapping.ReferenceMapping.createPerImplementationColumnsForReferenceField(ReferenceMapping.java:288)
at org.datanucleus.store.mapped.mapping.ReferenceMapping.prepareDatastoreMapping(ReferenceMapping.java:210)
at org.datanucleus.store.mapped.mapping.ReferenceMapping.initialize(ReferenceMapping.java:106)
at org.datanucleus.store.mapped.mapping.InterfaceMapping.initialize(InterfaceMapping.java:52)
at org.datanucleus.store.mapped.mapping.MappingFactory.createMapping(MappingFactory.java:97)
at org.datanucleus.store.mapped.mapping.AbstractMappingManager.getMapping(AbstractMappingManager.java:263)
at com.google.appengine.datanucleus.mapping.DatastoreTable.addFieldMapping(DatastoreTable.java:491)
at com.google.appengine.datanucleus.mapping.DatastoreTable.initializeNonPK(DatastoreTable.java:436)
at com.google.appengine.datanucleus.mapping.DatastoreTable.buildMapping(DatastoreTable.java:374)
at com.google.appengine.datanucleus.DatastoreManager.buildStoreData(DatastoreManager.java:439)
at com.google.appengine.datanucleus.DatastoreManager.newStoreData(DatastoreManager.java:403)
at org.datanucleus.store.AbstractStoreManager.addClasses(AbstractStoreManager.java:1183)
at org.datanucleus.store.AbstractStoreManager.addClass(AbstractStoreManager.java:1157)
at org.datanucleus.store.mapped.MappedStoreManager.getDatastoreClass(MappedStoreManager.java:407)
at com.google.appengine.datanucleus.DatastoreManager.getDatastoreClass(DatastoreManager.java:544)
at com.google.appengine.datanucleus.query.DatastoreQuery.compile(DatastoreQuery.java:234)
at com.google.appengine.datanucleus.query.JPQLQuery.performExecute(JPQLQuery.java:170)
at org.datanucleus.store.query.Query.executeQuery(Query.java:1789)
at org.datanucleus.store.query.Query.executeWithMap(Query.java:1693)
at org.datanucleus.api.jpa.JPAQuery.getSingleResult(JPAQuery.java:232)
Following are the versions that I was using (Java8) and using even now (Java11):
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-api-jpa</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>com.google.appengine.orm</groupId>
<artifactId>datanucleus-appengine</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-enhancer</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-core</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.jdo</groupId>
<artifactId>jdo-api</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>6.0</version>
</dependency>
<plugin>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-maven-plugin</artifactId>
<!-- <version>5.0.2</version> -->
<version>4.0.0-release</version>
<configuration>
<api>JPA</api>
<persistenceUnitName>transactions-optional</persistenceUnitName>
<log4jConfiguration>${basedir}/log4j.properties</log4jConfiguration>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.25</version>
<scope>runtime</scope>
</dependency>
I believe I am adhering to the compatibility shown here. To reiterate, the above used to work as expected when I was using the earlier GAE configuration.
So I am unable to determine if this is a Java11 issue or a Jersey2.25 issue or a DataNucleus3.11 issue or a datanucleus-appengine issue or a combination thereof. More importantly, how does one solve this issue? Are there some other versions of the above that I need to use for Java11? The alternative that I am contemplating right now is to plug out DataNucleus and perform database I/O using native API exposed by GAE Datastore thereby eliminating one (rather important) dependency.
Modified: As per this link, it seems that moving away from DataNucleus is the only option. Any opinions?