I'm stuck with some misconfiguration of some kind using datanucleus & JDO within an stand-alone Java web app (which uses Jetty, Servlets [yes the architecture is kinda old] and spring).
We are currently working on a new version; the original project didn't had any dependency update in the past 3 years; so we wanted to have those nice security, performance & functionallity upgrades, but as it was expected, the upgrade wasn't that easy.
Most of the problems we had have been already fixed, but one that is becoming really tedious has not:
We are using datanucleus + JDO to acces the underlying database; mainly because it was already there and beacause most of the system is really tied to it. So far, we can confirm that datanucleus can read the database (the debugger shows a non-null result coming from the database which correcty represents the default user; and some other dummy results from active endpoints). But when datanucleus tries to cache the results, it just goes into a dead end.
The error stack is the following:
GRAVE: exception catched
javax.jdo.JDOException: Failed to set object CachedPC : cls=mobi.allshoppings.model.User version=null loadedFlags=[YYYYYYYYYYYYYYYYY] with id com.inodes.datanucleus.model.Key:User("admin") into Redis cache
at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:680)
at org.datanucleus.api.jdo.JDOPersistenceManager.getObjectById(JDOPersistenceManager.java:1747)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:144)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:108)
at mobi.allshoppings.bdb.tools.BasicDataBuilder.warmUp(BasicDataBuilder.java:49)
at mobi.allshoppings.bdb.tools.InitAppServlet.init(InitAppServlet.java:21)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:616)
at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:396)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:871)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:298)
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1349)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1342)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:741)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:505)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.server.Server.start(Server.java:387)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.Server.doStart(Server.java:354)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at mobi.allshoppings.jetty.JettyServer.startup(JettyServer.java:62)
at mobi.allshoppings.cli.StartServer.main(StartServer.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at mobi.allshoppings.cli.CLI.main(CLI.java:100)
NestedThrowablesStackTrace:
Failed to set object CachedPC : cls=mobi.allshoppings.model.User version=null loadedFlags=[YYYYYYYYYYYYYYYYY] with id com.inodes.datanucleus.model.Key:User("admin") into Redis cache
org.datanucleus.exceptions.NucleusException: Failed to set object CachedPC : cls=mobi.allshoppings.model.User version=null loadedFlags=[YYYYYYYYYYYYYYYYY] with id com.inodes.datanucleus.model.Key:User("admin") into Redis cache
at org.datanucleus.cache.redis.RedisLevel2Cache.put(RedisLevel2Cache.java:280)
at org.datanucleus.ExecutionContextImpl.putObjectIntoLevel2CacheInternal(ExecutionContextImpl.java:4914)
at org.datanucleus.ExecutionContextImpl.putObjectIntoLevel2Cache(ExecutionContextImpl.java:4741)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3579)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3016)
at org.datanucleus.api.jdo.JDOPersistenceManager.getObjectById(JDOPersistenceManager.java:1742)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:144)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:108)
at mobi.allshoppings.bdb.tools.BasicDataBuilder.warmUp(BasicDataBuilder.java:49)
at mobi.allshoppings.bdb.tools.InitAppServlet.init(InitAppServlet.java:21)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:616)
at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:396)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:871)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:298)
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1349)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1342)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:741)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:505)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.server.Server.start(Server.java:387)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.Server.doStart(Server.java:354)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at mobi.allshoppings.jetty.JettyServer.startup(JettyServer.java:62)
at mobi.allshoppings.cli.StartServer.main(StartServer.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at mobi.allshoppings.cli.CLI.main(CLI.java:100)
As the stack shows, the exception is fired during the serialization process. I'm aware that any class that will be stored using datanucleus must extend Serializable and must use some special annotations, like @PersistenceCapable, @NotPersistant or @EmbebedOnly
The thing is that, the current in-production version has the very same configuration, the only changes made that could broken any datanucleus configuration was the upgrade itself and the declaration of two new classes, which: have been already annotated (as in the documentation and as in other working classes) and those classes are not involved at all in the statup process, so even if their configuration is bad, the server should start just fine; but it refuses to. The persitence.xml and package-mongodb.orm seem just fine (again, as in the documentation and as in other working classes).
The datanucleus enhanchement process and dependency addition into classpath are; as far we know, correct.
The Non-Serializable exception that gets reaised during the serialization process is caused due a (malformed?) CachePC object (builded by datanucleus to wrap the actual User object), which has a field that is an instance of StateManagerImpl and appearently does not implements Serializable, hece causing the exception.
Note: the stacktrace above matches the current configuration of the project and it does not shows directly a NoSerializableException, but while debbuging I confirmed this is the first exception raised. It gets raised when ObjectOutputStream determines that StateManagerImpl isn't a valid object to serialize. The current version uses XMemcached, if we switch this version to Memcached, we can clearly see a "Non-Serializable Exception". (we want to switch to Redis because the original server was designed to be a distributed system; but you would get surprise of how manny bottle necks it has)
So; we don't know why it tries to serialize StateManagerImpl; we thought it was a bug on the last datanucleus version, so we switched to version 5.1.0-release with no success. The app, the Jetty server & the servlets start just fine, we can confirm that datanucleus parses the datanucleus.configuration file sucessfully and we can obtain PersistanceManager instances and read mongo database. But when it comes into writting in the cache (which is done automatically); Redis or XMemcached, we always get a Non-Serializable exception because datanucleus builds a CachedPC with a non-serializable StateManagerImpl.
Where should we re-start? What could be wrong? Should we switch datanucleus for a more supported data access layer?
Thanks in advaice.
UPDATE
The following is the stack trace produced when using Memcached instead of Redis (the behaviour is the same, it breaks when serializing into L2 Cache again)
GRAVE: exception catched
javax.jdo.JDOException: Exception thrown in persistence to xmemcached
at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:676)
at org.datanucleus.api.jdo.JDOPersistenceManager.getObjectById(JDOPersistenceManager.java:1747)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:144)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:108)
at mobi.allshoppings.bdb.tools.BasicDataBuilder.warmUp(BasicDataBuilder.java:49)
at mobi.allshoppings.bdb.tools.InitAppServlet.init(InitAppServlet.java:21)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:616)
at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:396)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:871)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:298)
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1349)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1342)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:741)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:505)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.server.Server.start(Server.java:387)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.Server.doStart(Server.java:354)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at mobi.allshoppings.jetty.JettyServer.startup(JettyServer.java:62)
at mobi.allshoppings.cli.StartServer.main(StartServer.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at mobi.allshoppings.cli.CLI.main(CLI.java:100)
NestedThrowablesStackTrace:
java.lang.IllegalArgumentException: Non-serializable object
at net.rubyeye.xmemcached.transcoders.BaseSerializingTranscoder.serialize(BaseSerializingTranscoder.java:99)
at net.rubyeye.xmemcached.transcoders.SerializingTranscoder.encode(SerializingTranscoder.java:211)
at net.rubyeye.xmemcached.command.text.TextStoreCommand.encodeValue(TextStoreCommand.java:199)
at net.rubyeye.xmemcached.command.text.TextStoreCommand.encode(TextStoreCommand.java:155)
at net.rubyeye.xmemcached.impl.MemcachedTCPSession.wrapMessage(MemcachedTCPSession.java:189)
at com.google.code.yanf4j.core.impl.AbstractSession.write(AbstractSession.java:383)
at net.rubyeye.xmemcached.impl.MemcachedConnector.send(MemcachedConnector.java:556)
at net.rubyeye.xmemcached.XMemcachedClient.sendCommand(XMemcachedClient.java:322)
at net.rubyeye.xmemcached.XMemcachedClient.sendStoreCommand(XMemcachedClient.java:2537)
at net.rubyeye.xmemcached.XMemcachedClient.set(XMemcachedClient.java:1369)
at net.rubyeye.xmemcached.XMemcachedClient.set(XMemcachedClient.java:1428)
at net.rubyeye.xmemcached.XMemcachedClient.set(XMemcachedClient.java:1415)
at org.datanucleus.cache.xmemcached.XmemcachedLevel2Cache.put(XmemcachedLevel2Cache.java:177)
at org.datanucleus.ExecutionContextImpl.putObjectIntoLevel2CacheInternal(ExecutionContextImpl.java:4914)
at org.datanucleus.ExecutionContextImpl.putObjectIntoLevel2Cache(ExecutionContextImpl.java:4741)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3579)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3016)
at org.datanucleus.api.jdo.JDOPersistenceManager.getObjectById(JDOPersistenceManager.java:1742)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:144)
at mobi.allshoppings.dao.spi.GenericDAOJDO.get(GenericDAOJDO.java:108)
at mobi.allshoppings.bdb.tools.BasicDataBuilder.warmUp(BasicDataBuilder.java:49)
at mobi.allshoppings.bdb.tools.InitAppServlet.init(InitAppServlet.java:21)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:616)
at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:396)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:871)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:298)
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1349)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1342)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:741)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:505)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.server.Server.start(Server.java:387)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.Server.doStart(Server.java:354)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at mobi.allshoppings.jetty.JettyServer.startup(JettyServer.java:62)
at mobi.allshoppings.cli.StartServer.main(StartServer.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at mobi.allshoppings.cli.CLI.main(CLI.java:100)
Caused by: java.io.NotSerializableException: org.datanucleus.state.StateManagerImpl
- field (class "org.datanucleus.identity.IdentityReference", name: "client", type: "class java.lang.Object")
- object (class "org.datanucleus.identity.IdentityReference", org.datanucleus.identity.IdentityReference@44fd7ba4)
- field (class "org.datanucleus.cache.CachedPC", name: "id", type: "class java.lang.Object")
- object (class "org.datanucleus.cache.CachedPC", CachedPC : cls=mobi.allshoppings.model.Address version=null loadedFlags=[YYYYYYYYY])
- custom writeObject data (class "java.util.HashMap")
- object (class "java.util.HashMap", {0=1, 1=CachedPC : cls=mobi.allshoppings.model.Address version=null loadedFlags=[YYYYYYYYY], 2=null, 3=null, 4=CachedPC : cls=mobi.allshoppings.model.ContactInfo version=null loadedFlags=[YYYYYYYYYYYY], 5=Sun Oct 29 04:57:34 CST 2017, 6=null, 7=true, 8=User("admin"), 9=null, 10=Sun Oct 29 05:03:40 CST 2017, 11=0, 12=true, 13=CachedPC : cls=mobi.allshoppings.model.UserSecurity version=null loadedFlags=[YYYYYYYYYYYYYYYYY], 14=null, 15=00000000880E0D76, 16=CachedPC : cls=mobi.allshoppings.model.tools.ViewLocation version=null loadedFlags=[Y]})
- field (class "org.datanucleus.cache.CachedPC", name: "fieldValues", type: "interface java.util.Map")
- root object (class "org.datanucleus.cache.CachedPC", CachedPC : cls=mobi.allshoppings.model.User version=null loadedFlags=[YYYYYYYYYYYYYYYYY])
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1182)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at java.util.HashMap.internalWriteEntries(HashMap.java:1790)
at java.util.HashMap.writeObject(HashMap.java:1363)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1128)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at net.rubyeye.xmemcached.transcoders.BaseSerializingTranscoder.serialize(BaseSerializingTranscoder.java:94)
... 48 more
Also, the following are state of the ObjectOutputStream's debugInfoStack before the actual exception throw from the serialization process:
This is the state just before the exception creation:
- object (class "java.lang.StackTraceElement", java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1182))
- element of array (index: 0)
- array (class "[Ljava.lang.StackTraceElement;", size: 74)
- field (class "java.lang.Throwable", name: "stackTrace", type: "class [Ljava.lang.StackTraceElement;")
- custom writeObject data (class "java.lang.Throwable")
- root object (class "java.io.NotSerializableException", java.io.NotSerializableException: org.datanucleus.state.StateManagerImpl
- field (class "org.datanucleus.identity.IdentityReference", name: "client", type: "class java.lang.Object")
- object (class "org.datanucleus.identity.IdentityReference", org.datanucleus.identity.IdentityReference@44fd7ba4)
- field (class "org.datanucleus.cache.CachedPC", name: "id", type: "class java.lang.Object")
- object (class "org.datanucleus.cache.CachedPC", CachedPC : cls=mobi.allshoppings.model.Address version=null loadedFlags=[YYYYYYYYY])
- custom writeObject data (class "java.util.HashMap")
- object (class "java.util.HashMap", {0=1, 1=CachedPC : cls=mobi.allshoppings.model.Address version=null loadedFlags=[YYYYYYYYY], 2=null, 3=null, 4=CachedPC : cls=mobi.allshoppings.model.ContactInfo version=null loadedFlags=[YYYYYYYYYYYY], 5=Sun Oct 29 04:57:34 CST 2017, 6=null, 7=true, 8=User("admin"), 9=null, 10=Sun Oct 29 05:03:40 CST 2017, 11=0, 12=true, 13=CachedPC : cls=mobi.allshoppings.model.UserSecurity version=null loadedFlags=[YYYYYYYYYYYYYYYYY], 14=null, 15=00000000880E0D76, 16=CachedPC : cls=mobi.allshoppings.model.tools.ViewLocation version=null loadedFlags=[Y]})
- field (class "org.datanucleus.cache.CachedPC", name: "fieldValues", type: "interface java.util.Map")
- root object (class "org.datanucleus.cache.CachedPC", CachedPC : cls=mobi.allshoppings.model.User version=null loadedFlags=[YYYYYYYYYYYYYYYYY]))
This state displays a suppressedException I hadn't noticed before (and one of the last states before firing the exception):
- object (class "java.util.ArrayList", [])
- field (class "java.util.Collections$UnmodifiableCollection", name: "c", type: "interface java.util.Collection")
- object (class "java.util.Collections$UnmodifiableList", [])
- field (class "java.lang.Throwable", name: "suppressedExceptions", type: "interface java.util.List")
- custom writeObject data (class "java.lang.Throwable")
- root object (class "java.io.NotSerializableException", java.io.NotSerializableException: org.datanucleus.state.StateManagerImpl
- field (class "org.datanucleus.identity.IdentityReference", name: "client", type: "class java.lang.Object")
- object (class "org.datanucleus.identity.IdentityReference", org.datanucleus.identity.IdentityReference@44fd7ba4)
- field (class "org.datanucleus.cache.CachedPC", name: "id", type: "class java.lang.Object")
- object (class "org.datanucleus.cache.CachedPC", CachedPC : cls=mobi.allshoppings.model.Address version=null loadedFlags=[YYYYYYYYY])
- custom writeObject data (class "java.util.HashMap")
- object (class "java.util.HashMap", {0=1, 1=CachedPC : cls=mobi.allshoppings.model.Address version=null loadedFlags=[YYYYYYYYY], 2=null, 3=null, 4=CachedPC : cls=mobi.allshoppings.model.ContactInfo version=null loadedFlags=[YYYYYYYYYYYY], 5=Sun Oct 29 04:57:34 CST 2017, 6=null, 7=true, 8=User("admin"), 9=null, 10=Sun Oct 29 05:03:40 CST 2017, 11=0, 12=true, 13=CachedPC : cls=mobi.allshoppings.model.UserSecurity version=null loadedFlags=[YYYYYYYYYYYYYYYYY], 14=null, 15=00000000880E0D76, 16=CachedPC : cls=mobi.allshoppings.model.tools.ViewLocation version=null loadedFlags=[Y]})
- field (class "org.datanucleus.cache.CachedPC", name: "fieldValues", type: "interface java.util.Map")
- root object (class "org.datanucleus.cache.CachedPC", CachedPC : cls=mobi.allshoppings.model.User version=null loadedFlags=[YYYYYYYYYYYYYYYYY]))
The only class holding Lists as attributes, is an attribute of the User class, which has the following declaration:
@PersistenceCapable(detachable="true")
@EmbeddedOnly
public class UserSecurity implements Serializable {
And I don't see it being called during the caching process, only during the mongodb reading. Again: lectures to mongodb work well, but as datanucleus tryies to cache the just readed object; it fails. So, I don't know from where that unmodificable list is coming.
So, maybe I was being a little too salty; but it turns out that actually our problem was caused by a Datanucleus bug: https://github.com/datanucleus/datanucleus-core/issues/283
The docs says that embedded objects shouldn't have an ID, since they are directly liked to the container object which has an ID (under the "same table" scheme) http://www.datanucleus.org/products/datanucleus/jdo/mapping.html#embedded_pc But our embedded objects were given a IdentityReference which shouldn't be there.
I noticed that the StateManagerImpl was the cause of the exception when serializing the embedded objects, but I didn't put much attention on the IdentityReference object which lead to the serialization of the StateManagerImpl; causing the errors on cache L2 writting. This is what the bug is all about.
So, the solution was to clone the datanucleus-core project, build and install the latest version locally and re-build our project changing the datanuclues-core dependency to a local file. Its working just great.
After diving deep on the documentation of datanucleus and its code itself, I'm more convinced that datanucleus is actually a very nice datastore abstraction, and we'll keep it on our project (but I still believe that support and error messages are vague)