title: DataNucleus casting serialized objects
body: <p>I have an application using DataNucleus/JDO on Google App Engine, and I'm attempting to make a pool of persisted objects so user requests can simply fetch a key instead of waiting for a new object to be persisted.  </p>
  
  <p>The object pool is held in an ArrayBlockingQueue&lt;Key&gt;, and every time a user requests a new Key I pop one from the queue and spawn a DeferredTask to persist a new object and add it to the queue in a separate thread, so the Key can be returned to the user quickly:</p>
  
  <pre><code>@PersistenceCapable
  public class EquipmentStock implements Serializable {
  
      ...
  
      @Persistent(serialized="true")
      private ArrayBlockingQueue&lt;Key&gt; blockingQueue;
  
      public Key getEquipmentKey() throws IllegalArgumentException, InterruptedException {
          Key key = blockingQueue.take();
  
          QueueFactory.getDefaultQueue().add(withDefaults().payload(new DeferredTask() {
              @Override
              public void run() {
                  PersistenceManager pm = PMF.getInstance().getPersistenceManager();
  
                  try {
                      EquipmentItemData equipmentData = ObjectFetcher.fetchObjectByID(pm, EquipmentItemData.class, equipmentID, true);
                      EquipmentItem equipmentItem = new EquipmentItem(equipmentData);
  
                      pm.makePersistent(equipmentItem);
  
                      blockingQueue.put(equipmentItem.getKey());
                  }
                  ...
              }
          }));
  
          return key;
  
      }
  }
  </code></pre>
  
  <p>When the application shuts down/restarts, I need to save/load the contents of the queue.  GAE doesn't support persisting ArrayBlockingQueues, so I attempted to persist the queue as a serialized object, but it fails to load with a ClassCastException:</p>
  
  <pre><code>Failed startup of context com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@12b17d0{...}
  java.lang.ClassCastException: org.datanucleus.store.types.sco.simple.Collection cannot be cast to java.util.concurrent.ArrayBlockingQueue
      at {...}.EquipmentStock.jdoReplaceField(EquipmentStock.java)
      at org.datanucleus.state.AbstractStateManager.replaceField(AbstractStateManager.java:2387)
      at org.datanucleus.state.JDOStateManager.replaceField(JDOStateManager.java:1877)
      at org.datanucleus.state.JDOStateManager.replaceField(JDOStateManager.java:1781)
      at org.datanucleus.store.types.sco.SCOUtils.createSCOWrapper(SCOUtils.java:241)
      at org.datanucleus.store.types.sco.SCOUtils.newSCOInstance(SCOUtils.java:139)
      at org.datanucleus.state.JDOStateManager.wrapSCOField(JDOStateManager.java:2230)
      at org.datanucleus.state.JDOStateManager.replaceAllLoadedSCOFieldsWithWrappers(JDOStateManager.java:2115)
      at com.google.appengine.datanucleus.DatastorePersistenceHandler.insertObjectsInternal(DatastorePersistenceHandler.java:372)
      at com.google.appengine.datanucleus.DatastorePersistenceHandler.insertObject(DatastorePersistenceHandler.java:218)
      at org.datanucleus.state.JDOStateManager.internalMakePersistent(JDOStateManager.java:2381)
      at org.datanucleus.state.JDOStateManager.makePersistent(JDOStateManager.java:2357)
      at org.datanucleus.ObjectManagerImpl.persistObjectInternal(ObjectManagerImpl.java:1896)
      at org.datanucleus.ObjectManagerImpl.persistObjectWork(ObjectManagerImpl.java:1745)
      at org.datanucleus.ObjectManagerImpl.persistObject(ObjectManagerImpl.java:1602)
      at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:731)
      at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:756)
      at {...}.EquipmentStockLocator.initStock(EquipmentStockLocator.java:57)
      at {...}.BootstrapListener.contextInitialized(BootstrapListener.java:13)
      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 com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:219)
      at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:194)
      at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
      at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
      at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:437)
      at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:444)
      at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:188)
      at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:308)
      at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:300)
      at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:441)
      at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
      at java.lang.Thread.run(Thread.java:724)
  </code></pre>
  
  <p>As far as I can tell, DataNucleus is casting the ArrayBlockingQueue to its generic Collection class, but failing to cast it back when the application restarts, presumably because casting to Collection discarded ArrayBlockingQueue's fixed size data.<br>
  What I don't understand is why it's casting the ArrayBlockingQueue in the first place, since I specified that it should be stored as a single serialized blob.</p>