ClassCastException: com.google.appengine.api.datastore.Entity cannot be cast to XXX

1,227 views
Skip to first unread message

Cim balli

unread,
Jun 23, 2014, 1:15:38 PM6/23/14
to objectify...@googlegroups.com
What steps will reproduce the problem?

I recently added a new entity to my project with 2 fields :
@Id String id
@Serialize Serializable value

When calling ObjectifyService.ofy().load().type(SessionDatastore.class).id(id).now();
from time to time I got the exception java.lang.ClassCastException: com.google.appengine.api.datastore.Entity cannot be cast to SessionDatastore The exception is not so frequent but when it occurs on a specific instance, then it repeats multiple times for that entity. What version of the product are you using? On what operating system? Objectify 5.0.3 Also got the problem with Objectify 4.0rc2, that's why I updated.

Stacktrace

java.lang.ClassCastException: com.google.appengine.api.datastore.Entity cannot be cast to SessionDatastore
	at SessionDatastoreDao.get(SessionDatastoreDao.java:32)
	at DatastoreSessionDAO.doReadSession(DatastoreSessionDAO.java:80)
	at org.apache.shiro.session.mgt.eis.AbstractSessionDAO.readSession(AbstractSessionDAO.java:168)
	at org.apache.shiro.session.mgt.DefaultSessionManager.retrieveSessionFromDataSource(DefaultSessionManager.java:236)
	at org.apache.shiro.session.mgt.DefaultSessionManager.retrieveSession(DefaultSessionManager.java:222)
	at org.apache.shiro.session.mgt.AbstractValidatingSessionManager.doGetSession(AbstractValidatingSessionManager.java:118)
	at org.apache.shiro.session.mgt.AbstractNativeSessionManager.lookupSession(AbstractNativeSessionManager.java:108)
	at org.apache.shiro.session.mgt.AbstractNativeSessionManager.getSession(AbstractNativeSessionManager.java:100)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:125)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at org.apache.shiro.web.subject.WebSubject$Builder.buildWebSubject(WebSubject.java:148)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.createSubject(AbstractShiroFilter.java:292)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:359)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.googlecode.objectify.cache.AsyncCacheFilter.doFilter(AsyncCacheFilter.java:58)
	at com.googlecode.objectify.ObjectifyFilter.doFilter(ObjectifyFilter.java:48)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at CookieRemoverFilter.doFilter(CookieRemoverFilter.java:68)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:125)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:60)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:254)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
	at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:76)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:146)
	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)

The trace SessionDatastoreDao.get(SessionDatastoreDao.java:32) corresponds to the code :
final SessionDatastore sessionDatastore = ObjectifyService.ofy().load().type(SessionDatastore.class).id(id).now();

Thanks for your help !

Jeff Schnitzer

unread,
Jun 23, 2014, 1:29:38 PM6/23/14
to objectify...@googlegroups.com
Have you registered SessionDatastore.class?

Jeff


--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appen...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Cim balli

unread,
Jun 23, 2014, 6:49:28 PM6/23/14
to objectify...@googlegroups.com, je...@infohazard.org
Yes, like for all other entities in the project.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.

Nicholas Okunew

unread,
Jun 23, 2014, 7:12:04 PM6/23/14
to objectify...@googlegroups.com, je...@infohazard.org
Do you have any classes with the same entity name? Check the entity annotation and make sure the underlying kind is unique.
I've had issues with colliding kind names in objectify4 before. Ofy4 doesn't check they're unique when you register - it's quite possible 5 doesn't either.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appen...@googlegroups.com.

Cimballi

unread,
Jun 23, 2014, 7:21:13 PM6/23/14
to objectify...@googlegroups.com
Thanks for the help. All my "model" classes are in the same package, and I do not specify custom name, so java class name is used. So no risk of conflict in this case.
In order to not be blocked I switched the DAO.get method to native datastore API. Still using Objectify for save and delete, for now it seems to be working but I would prefer solve the root problem.


--
You received this message because you are subscribed to a topic in the Google Groups "objectify-appengine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/objectify-appengine/_0rNUCgzbdo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to objectify-appen...@googlegroups.com.

Jeff Schnitzer

unread,
Jun 23, 2014, 7:25:06 PM6/23/14
to objectify...@googlegroups.com
Try posting more code. Show the full definition of SessionDatastore _exactly_ as you have typed it.

This makes no sense. It especially makes no sense if you say this is intermittent - are you sure you this load ever succeeds?

Jeff

Cimballi

unread,
Jun 23, 2014, 7:33:07 PM6/23/14
to objectify...@googlegroups.com
I know it's really strange, and I'd like to help more in order to find what's the problem is but I don't know what to do.
There is another point, but I am not 100% sure. It seems the first time the problem occurs for a specific instance of the entity, either the problem itself fires the creation of a new GAE instance, either the problem is generated by the creation of a new GAE instance. Honestly, it's not sure, but I noticed this fact a couple of times. But for sure most of the times it works.


Here is the class without the getters and setters :

import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Serialize;
import com.googlecode.objectify.annotation.Unindex;

import java.io.Serializable;

import org.apache.shiro.session.Session;

/**
 */
@Entity
@Unindex
public class SessionDatastore implements Serializable {

    /**
     */
    private static final long serialVersionUID = -3844076568132458122L;

    /**
     */
    private Long creationDate;

    /**
     */
    private Long modificationDate;

    /**
     */
    @Serialize
    private Session session;

    /**
     */
    @Id
    private String sessionId;

    /**
     */
    public SessionDatastore() {
        super();
    }
}

Jeff Schnitzer

unread,
Jun 23, 2014, 7:42:41 PM6/23/14
to objectify...@googlegroups.com
This sounds like you have some sort of race condition on registering entities. How/when do you do it?

When objectify loads a key and gets a value but doesn't know what to do with it, objectify will return the entity raw. Sounds like you're loading an unregistered type.

Jeff

Cimballi

unread,
Jun 23, 2014, 8:07:27 PM6/23/14
to objectify...@googlegroups.com
Ok Jeff, so this is really interesting because at least now we know that in a specific situation Objectify returns the GAE "Entity" object. It makes the error more "understandable". Now the problem is, why do I face this specific situation ? The entities are all registered in a static bloc in a class. And I have the following configuration in web.xml :
Objectify Filter
Shiro Filter -> Uses the SessionDatastore entity
Main servlet -> uses the class with the static bloc

Before I add the SessionDatastore everything was ok, and it's still ok for the other entities.
So in fact because the SessionDatastore entity is used in the Shiro Filter, maybe I should also update the Objectify registration step and ensure it's done before the Objectify Filter.

What do you think ?

Jeff Schnitzer

unread,
Jun 23, 2014, 8:09:55 PM6/23/14
to objectify...@googlegroups.com
The exact loading order of static blocks can be tricky, which is why I suggest this:


Alternatively, do it in a servlet context listener - those are pretty much the first thing executed.

Jeff

Nicholas Okunew

unread,
Jun 23, 2014, 8:16:03 PM6/23/14
to objectify...@googlegroups.com
static blocks are loaded when a class is loaded, and formally a class being loaded is defined as both the class itself, and the classloader that loads it. Therefore, you can actually have a static block loaded more than once in a code base (because the class is loaded multiple times).
Definitely avoid this - in the best case it will just work, in the worst case you get weird errors like you describe.

Jeff - is it possible that the raw entity would be returned when instantiation of the instance or a nested instance fails - for example if his Session object cannot be deserialized?

Jeff Schnitzer

unread,
Jun 23, 2014, 8:25:05 PM6/23/14
to objectify...@googlegroups.com
If an error occurs you will get an exception. There is only one code path that should cough up the raw Entity, LoadEngine.java line 183, and it's pretty explicit.

I don't think static code blocks are quite that dangerous - in the case of a web application instance any individual class should be loaded only once. But if you're not careful it's easy to get in the state where Objectify is running before the relevant class has been loaded. It's safe advice that unless you really know what you're doing, don't use them to register entities. Or follow the example in BestPractices quite rigidly.

Jeff

Cimballi

unread,
Jun 25, 2014, 9:56:25 AM6/25/14
to objectify...@googlegroups.com
I used a listener to register the entities and no error yesterday. It seems that was the problem.

I would advice you put the exception message somewhere in the docs and mention that if someone faces this error then it's probably a problem with entity registration. May help other developers.

Thanks a lot for your help and for the Objectify API !

Jeff Schnitzer

unread,
Jun 25, 2014, 11:56:39 AM6/25/14
to objectify...@googlegroups.com
Done, this is now a FAQ. Thanks.

Jeff

Alex Rhomberg

unread,
Jul 9, 2014, 2:58:22 AM7/9/14
to objectify...@googlegroups.com
The best practices method for registering seems to have solved it for me as well. My registering took place in the static code of all servlets (as recommended in the Entity docs), but not in the GWT RemoteServiceServlet, which seems to be sometimes loaded in a different VM.

Could you please adapt the other docs and point to the best practices both in the Entity doc (section registering) and in the Setup doc for Eclipse, where the static import must be changed to the custom OfyService.

Regards
Alex
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsubscribe...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "objectify-appengine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/objectify-appengine/_0rNUCgzbdo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to objectify-appengine+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "objectify-appengine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/objectify-appengine/_0rNUCgzbdo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to objectify-appengine+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "objectify-appengine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/objectify-appengine/_0rNUCgzbdo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to objectify-appengine+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "objectify-appengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objectify-appengine+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "objectify-appengine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/objectify-appengine/_0rNUCgzbdo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to objectify-appengine+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages