google-code-export / objectify-appengine

Automatically exported from code.google.com/p/objectify-appengine
MIT License
1 stars 0 forks source link

Cast exception in transcaction handling #168

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
This occures not really often, mostly at application start (when handling first 
or second http request)

Exception occures sometimes:
Caused by: java.lang.ClassCastException: 
com.google.appengine.api.datastore.TransactionImpl cannot be cast to 
com.googlecode.objectify.cache.CachingTransaction
    at com.googlecode.objectify.cache.CachingAsyncDatastoreService$5.trigger(CachingAsyncDatastoreService.java:442)
    at com.googlecode.objectify.cache.TriggerFuture.isDone(TriggerFuture.java:89)
    at com.googlecode.objectify.cache.TriggerFuture.get(TriggerFuture.java:104)
    at com.googlecode.objectify.impl.ResultAdapter.now(ResultAdapter.java:34)
    at com.googlecode.objectify.util.ResultWrapper.translate(ResultWrapper.java:22)
    at com.googlecode.objectify.util.ResultWrapper.translate(ResultWrapper.java:10)
    at com.googlecode.objectify.util.ResultTranslator.nowUncached(ResultTranslator.java:21)
    at com.googlecode.objectify.util.ResultCache.now(ResultCache.java:30)
    at com.googlecode.objectify.util.ResultWrapper.translate(ResultWrapper.java:22)
    at com.googlecode.objectify.util.ResultWrapper.translate(ResultWrapper.java:10)
    at com.googlecode.objectify.util.ResultTranslator.nowUncached(ResultTranslator.java:21)
    at com.googlecode.objectify.util.ResultCache.now(ResultCache.java:30)

<Some user code>: ofy().save().entity(t).now()

    at com.googlecode.objectify.impl.TransactorNo.transactOnce(TransactorNo.java:113)
    at com.googlecode.objectify.impl.TransactorNo.transactNew(TransactorNo.java:90)
    at com.googlecode.objectify.impl.TransactorNo.transact(TransactorNo.java:80)
    at com.googlecode.objectify.impl.ObjectifyImpl.transact(ObjectifyImpl.java:177)

What version of the product are you using? 

appengine-java-sdk-1.8.1 
Objectify 4.0rc1

It looks this is an error in objectify.

Original issue reported on code.google.com by Nikolay....@gmail.com on 13 Jul 2013 at 4:24

GoogleCodeExporter commented 9 years ago
This is very peculiar. Is this still an issue? Is there anything you do 
explicitly in your code with Transaction objects?

Original comment by lhori...@gmail.com on 19 Oct 2013 at 7:05

GoogleCodeExporter commented 9 years ago
I suppose it appeared after some code changes.
Schema has changed: some object properties added/removed/changed.
It was only right after new version deployment.
Objects in global memory cache have some kind of wrong properties.

Original comment by Nikolay....@gmail.com on 19 Oct 2013 at 7:30

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
This is a test which reproduce failure.
The problem appears when registering classes with @Cached annotation inside 
transaction.
It's not a common case, but in my environment all classes are registered in 
static initialization block of some DAO class, and when first request to 
instance starts with transaction error occures.
Test:

package com.test;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.dev.HighRepJobPolicy;
import 
com.google.appengine.tools.development.testing.LocalBlobstoreServiceTestConfig;
import 
com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import 
com.google.appengine.tools.development.testing.LocalMemcacheServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Work;
import com.googlecode.objectify.annotation.Cache;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import org.junit.Before;
import org.junit.Test;

public class CastTest {
    @Entity
    @Cache
    static class DbTestEntity {
        @Id
        String id;

        DbTestEntity() {
        }

        DbTestEntity(String id) {
            this.id = id;
        }

        String getId() {
            return id;
        }
    }

    static class MyHighRepJobPolicy implements HighRepJobPolicy {
        MyHighRepJobPolicy() {
        }

        public boolean shouldApplyNewJob(Key key) {
            return true;
        }

        public boolean shouldRollForwardExistingJob(Key key) {
            return true;
        }
    }

    protected final LocalServiceTestHelper helper =
            new LocalServiceTestHelper(
                    new LocalDatastoreServiceTestConfig().setAlternateHighRepJobPolicyClass(MyHighRepJobPolicy.class),
                    new LocalMemcacheServiceTestConfig(),
                    new LocalBlobstoreServiceTestConfig());

    @Before
    public void doSetUp() throws Exception {
        helper.setUp();
    }

    @Test
    public void testTransaction() throws Exception {
        ObjectifyService.ofy().transact(new Work<Object>() {
            @Override
            public Object run() {
                ObjectifyService.register(DbTestEntity.class);
                DbTestEntity entity = new DbTestEntity("1234");
                ObjectifyService.ofy().save().entities(entity).now();
                return null;
            }
        });
    }
}

Original comment by Nikolay....@gmail.com on 13 Dec 2013 at 2:24

GoogleCodeExporter commented 9 years ago
You aren't allowed to register classes inside a transaction. The documentation 
on this is explicit: "Registration must be done at application startup, before 
Objectify is used."

The best place to register your entities is in your own OfyService:  
https://code.google.com/p/objectify-appengine/wiki/BestPractices#Use_Your_Own_Se
rvice

Original comment by lhori...@gmail.com on 3 Jan 2014 at 9:09

GoogleCodeExporter commented 9 years ago
Anyhow, thrown exception is not handled correctly and doesn't provide any 
useful information. It's produce only mess.

Original comment by boris.n....@gmail.com on 4 Jan 2014 at 7:44