are u sure u wont to proceed with that plan of changing out enhanced JDO classes? just sounds tooooo complicated.
-lp On Mar 3, 5:21 am, Jason G <ja...@bobberinteractive.com> wrote: > Hello everyone! > > We've run into a data migration-test problem, and I'm wondering if > anyone would have any advice on how to proceed... > > We're building a system that needs to allow hot-swapping of > application builds while customers are actively using our webapp, and > that means we need to support data object "schema" migration in- > place. We do this by implementing LoadCallback for version migration, > and @Deprecated-ing no-longer-used fields. So far, so good. > > Thing is, we'd like to build up a test suite that allows developers to > write unit tests for data migration against a local environment. That > means no uploading to GAE, but using > com.google.appengine.tools.development.testing.LocalServiceTestHelper > instead. > > We have two "classes" directories: Both containing DataNucleus-JDO- > enhanced .class files, one of the "old" schema, and one of the > current. > > We have a MigrationTestHelper that creates a GroovyClassLoader with > the old schema set as its classpath. The targetted class under test > is found, instantiated, and passed to a test-supplied Closure that > initializes the object with the old data to be migrated. The Helper > calls PersistenceManager.makePersistent and returns > pm.getObjectId(newlyPersisted).getKey(). > > The second half of the test involves creating a new GroovyClassLoader > and setting the context class loader: > Thread.currentThread().setContextClassLoader(loader). Then we use a > different PersistenceManager (from a different > PersistenceManagerFactory) to load the object by its Key. > > What happens is we get a ClassCastException: > java.lang.ClassCastException: java.lang.Long cannot be cast to > java.util.List > at com.x.model.User.jdoReplaceField(User.groovy) > at com.x.model.User.jdoReplaceFields(User.groovy) > at > org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java: > 2772) > at > org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java: > 2791) > at > org.datanucleus.store.appengine.DatastorePersistenceHandler.fetchObject(DatastorePersistenceHandler.java: > 480) > > It *appears* as though the JDOStateManagerImpl uses an array of fields > to get/set values. You can crack open the enhanced .class files and > see there's a method called __jdoFieldNamesInit() that sets up a > static list of Fields. > > The old User contains the field: "balance", which is a Long. > The new User contains the fields: "balance", which is @Deprecated and > is Long, and "_balances", which is a List. > > Looking in the .class files, it looks like each field is ordered > alphabetically, so in old User, "balance" is index 0, where in new > User, "balance" is index 1 and "_balances" is index 0. Hence the > ClassCastException. > > I'm stuck on how to proceed. I'd have thought that fields would be > replaced based on field name, not on an index... Especially an index > that we don't appear to be able to control. But if it's the case that > fields are placed by index on load, how does data migration work on > AppEngine itself? Our migration code works fine there... > > Is this a DataNucleus issue? An issue with LocalServiceTestHelper? > An issue of developer sanity? ;) > > Any insight would be greatly appriciated! > > Thanks! > Jason -- You received this message because you are subscribed to the Google Groups "Google App Engine for Java" group. To post to this group, send email to google-appengine-java@googlegroups.com. To unsubscribe from this group, send email to google-appengine-java+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=en.