GAE / java11 / Datastore / DataNucleus getting runtime exception: org.datanucleus.metadata.InvalidMemberMetaDataException

119 views Asked by At

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?

0

There are 0 answers