Objectify 4 sample app available

1,795 views
Skip to first unread message

Jeff Schnitzer

unread,
Dec 14, 2011, 11:27:17 AM12/14/11
to objectify...@googlegroups.com
I updated the Motomapia application for Objectify 4 trunk. The demo is here:

http://www.motomapia.com/

The source code is here:

https://github.com/stickfigure/motomapia

In particular, you will see examples of:

* Integrating Objectify4 with Guice

* "Make-your-own-Objectify-interface" using the wrapper classes

* Doing a "correct" integration of Resteasy and Guice

* Geohashing

It's going to be a while before I get the full documentation updated,
but this should be enough to get the early adopters started.

Jeff

Tristan Burch

unread,
Dec 21, 2011, 9:09:14 PM12/21/11
to objectify-appengine
Hi Jeff,

Would it be possible to periodically publish maven snapshots of
Objectify4 builds? I'd like to try it out and being able to depend on
a snapshot build instead of rolling my own build all the time would be
nice.

Thanks,
Tristan

Jeff Schnitzer

unread,
Dec 21, 2011, 11:02:41 PM12/21/11
to objectify...@googlegroups.com
Hmmmm. Sure, I can push snapshots into the maven repo... although I'm
on a borrowed laptop until mine comes back from repair and I don't
have all the maven crap set up on this box, so it may have to wait a
few days.

Jeff

--
We are the 20%

Tristan Burch

unread,
Dec 23, 2011, 12:52:05 PM12/23/11
to objectify...@googlegroups.com
No problem, thanks for doing this whenever you can.

-Tristan

Jeff Schnitzer

unread,
Dec 24, 2011, 12:47:08 PM12/24/11
to objectify...@googlegroups.com
I posted 4.0a1 to the maven repo. I don't plan on posting this to the
normal downloads because the documentation isn't ready yet... however
if you've been paying attention to the discussions on this mailing
list and are willing to read the javadocs you should do fine.

Here it is:

https://objectify-appengine.googlecode.com/svn/maven/com/googlecode/objectify/objectify/4.0a1/objectify-4.0a1.jar

Jeff

Emanuele Ziglioli

unread,
Jan 18, 2012, 4:10:06 PM1/18/12
to objectify-appengine
I'm interested to see how you've implemented geohashing, in the past I
recall one message of yours where you were going to use an other
service just for that but eventually dropped the idea.
I don't think GAE has started yet that service they've talked about in
the past IOs
Am using GeoPt fields for the time being :-)

Emanuele Ziglioli

unread,
Jan 18, 2012, 4:12:42 PM1/18/12
to objectify-appengine
Oh I see: you use http://code.google.com/p/javageomodel/
Now, that's a project I was going to use too!

Strangely enough, all my favourite java APIs seem to be inspired by
equivalent Python APIs, I might just as well start coding in Python
then!
http://www.sienaproject.com/index.html
https://github.com/ZiglioNZ/construct/


On Jan 19, 10:10 am, Emanuele Ziglioli <theb...@emanueleziglioli.it>
wrote:

Dominik Mayer

unread,
Feb 27, 2012, 2:49:57 PM2/27/12
to objectify...@googlegroups.com
I changed my app (running Objectify 4.0a3) according to the example but now I get the following error:

java.lang.NoSuchMethodError: com.googlecode.objectify.Objectify.setWrapper(Lcom/googlecode/objectify/Objectify;)V
at com.googlecode.objectify.util.cmd.ObjectifyWrapper.<init>(ObjectifyWrapper.java:33)
at com.myapp.server.db.Ofy.<init>(Ofy.java:11)
at com.myapp.server.db.OfyFactory.begin(OfyFactory.java:36)
at com.myapp.server.guice.GuiceServletConfig$ObjectifyModule.provideOfy(GuiceServletConfig.java:46)
[...]

Does anyone have an idea what the error could be?

Jeff Schnitzer

unread,
Feb 27, 2012, 3:01:53 PM2/27/12
to objectify...@googlegroups.com
Have you done a clean build?

NoSuchMethodError is a linker problem; basically your code is calling a method that doesn't exist in the jar.  You should only see this if you replace a jar with something incompatible without actually compiling your code against them.  This is the runtime equivalent of the compiler error you would normally see.

Jeff

Dominik Mayer

unread,
Feb 27, 2012, 4:08:10 PM2/27/12
to objectify...@googlegroups.com
Have you done a clean build?

Of my project: yes, of Objectify: no. I took the maven jar (objectify-4.0a3.jar + objectify-4.0a3-sources.jar). When I debug, the Exception is thrown at "this.base.setWrapper(this);" in the ObjectifyWrapper Constructor.

Jeff Schnitzer

unread,
Feb 27, 2012, 4:44:29 PM2/27/12
to objectify...@googlegroups.com
If you have built against Objectify then you shouldn't have a linker issue.

Any chance you have multiple objectify jars on your classpath?

Jeff

Dominik Mayer

unread,
Feb 27, 2012, 5:04:38 PM2/27/12
to objectify...@googlegroups.com

If you have built against Objectify then you shouldn't have a linker issue.

Any chance you have multiple objectify jars on your classpath?

Strange. There was no other objectify jar listed on the classpath but there was version 3.1 in the lib folder. After deleting it, the error went away. And is replaced by new ones. But those might be errors in my code. I'll try to fix them and and post the result.

Dominik Mayer

unread,
Feb 28, 2012, 7:00:48 AM2/28/12
to objectify...@googlegroups.com
Do I need "@RequestScoped" at the Ofy provider? With it, the dev server doesn't start:

Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.

And why does Objectify build the entities when they are registered? In my concrete case I have "this.register(MyClass.class);" in the OfyFacory. In the constructor of MyClass I inject the UserService and set a field to key of the user that's currently logged in. But while the server is started, there is no user signed in. I can work around this with an "initialize()" method that sets the key. Do I need to?

Jeff Schnitzer

unread,
Feb 28, 2012, 8:45:08 AM2/28/12
to objectify...@googlegroups.com
On Tue, Feb 28, 2012 at 7:00 AM, Dominik Mayer <domini...@gmail.com> wrote:
Do I need "@RequestScoped" at the Ofy provider? With it, the dev server doesn't start:

Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.

Are you sure you have enabled GuiceFilter?  Or is this being run from a test case?

The simple answer is no, you don't need @RequestScoped - but if you give it "dependent" scope then you'll get a fresh instance at every injection and won't get the benefits of session caching.  Maybe this doesn't matter to you.

If you're running this in a test case, I manually set up the request scope in setUp() and tear it down in tearDown().  This is, unfortunately, nontrivial.  Also nontrivial is getting task queues to work properly in the test environment.

I can probably add this to the Motomapia sample, but not in the next few days.  This is really a Guice/GAE problem.

And why does Objectify build the entities when they are registered? In my concrete case I have "this.register(MyClass.class);" in the OfyFacory. In the constructor of MyClass I inject the UserService and set a field to key of the user that's currently logged in. But while the server is started, there is no user signed in. I can work around this with an "initialize()" method that sets the key. Do I need to?

Do you have @IgnoreSave(IfDefault.class) enabled anywhere?  It constructs a default instance to find out with the default value for a field is.  There's no practical way around that.

Jeff

Dominik Mayer

unread,
Feb 28, 2012, 9:02:36 AM2/28/12
to objectify...@googlegroups.com
Are you sure you have enabled GuiceFilter?  Or is this being run from a test case?

It's not a test. I do have "filter("/*").through(AsyncCacheFilter.class);" in my ServletModule. The provideOfy method is not in a static class. Might that be the problem? (I'll try and move it back to the static class.) I also found posts that suggest this might be a Jetty error. But in that case, wouldn't it affect everyone using Objectify? Hm...
 
The simple answer is no, you don't need @RequestScoped - but if you give it "dependent" scope then you'll get a fresh instance at every injection and won't get the benefits of session caching.  Maybe this doesn't matter to you.

If you're running this in a test case, I manually set up the request scope in setUp() and tear it down in tearDown().  This is, unfortunately, nontrivial.  Also nontrivial is getting task queues to work properly in the test environment.

Ah, good to know.
 
I can probably add this to the Motomapia sample, but not in the next few days.  This is really a Guice/GAE problem.

That would be great.
 
Do you have @IgnoreSave(IfDefault.class) enabled anywhere?  It constructs a default instance to find out with the default value for a field is.  There's no practical way around that.

I don't. I also ran in another problem: I used to have a custom Datastore class that forwarded the calls to the DAO. With Objectify 4 I moved everything into the Ofy but I cannot inject the Ofy in my Entity because that would mean that the Ofy would have to be injected while the Ofy itself is being constructed. this.register(....class) → construct(...) → Inject Ofy. At least that's how I understand what's going on. The error message:

Tried proxying com.mitado.server.db.OfyFactory to support a circular dependency, but it is not an interface

Matthew Jaggard

unread,
Feb 28, 2012, 9:06:54 AM2/28/12
to objectify...@googlegroups.com
Just to save Jeff a bit of typing...

I think you need GuiceFilter. You enable it in your web.xml like this:

<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Dominik Mayer

unread,
Feb 28, 2012, 9:12:24 AM2/28/12
to objectify...@googlegroups.com
I think you need GuiceFilter. You enable it in your web.xml like this: 
 
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

I do have it (using app.yaml):

- url: /*
  filter: com.google.inject.servlet.GuiceFilter
  login: required

Jeff Schnitzer

unread,
Feb 28, 2012, 9:24:34 AM2/28/12
to objectify...@googlegroups.com
On Tue, Feb 28, 2012 at 9:02 AM, Dominik Mayer <domini...@gmail.com> wrote:
Are you sure you have enabled GuiceFilter?  Or is this being run from a test case?

It's not a test. I do have "filter("/*").through(AsyncCacheFilter.class);" in my ServletModule. The provideOfy method is not in a static class. Might that be the problem? (I'll try and move it back to the static class.) I also found posts that suggest this might be a Jetty error. But in that case, wouldn't it affect everyone using Objectify? Hm...

As Matthew pointed out, you need the GuiceFilter.  This is a standard part of Guice.
  
I can probably add this to the Motomapia sample, but not in the next few days.  This is really a Guice/GAE problem.

That would be great.
 
Do you have @IgnoreSave(IfDefault.class) enabled anywhere?  It constructs a default instance to find out with the default value for a field is.  There's no practical way around that.

Ah, I just realized that Objectify always constructs an instance of your class at register() to verify that it can, in fact, construct an instance of your class.  This is not a sanity check I would disable by default.  I could make it easier to override, but this feels like an antipattern that should be discussed.  For now, you can override the construct() method in ObjectifyFactory with your OfyFactory subclass:

public <T> T construct(Class<T> type) {
    try {
        return super.construct(type);
    } catch (RuntimeException ex) {
        if (type == MyEntityThing.class)
           return null;
        else
           throw ex;
    }
}

I don't. I also ran in another problem: I used to have a custom Datastore class that forwarded the calls to the DAO. With Objectify 4 I moved everything into the Ofy but I cannot inject the Ofy in my Entity because that would mean that the Ofy would have to be injected while the Ofy itself is being constructed. this.register(....class) → construct(...) → Inject Ofy. At least that's how I understand what's going on. The error message:

Tried proxying com.mitado.server.db.OfyFactory to support a circular dependency, but it is not an interface

This will go away when you remove construction-at-registration.  Possibly this is a compelling argument for allowing an easy override to disable that.  However, it won't work for IfDefault.class.

Jeff

Jeff Schnitzer

unread,
Feb 28, 2012, 9:26:28 AM2/28/12
to objectify...@googlegroups.com
On Tue, Feb 28, 2012 at 9:12 AM, Dominik Mayer <domini...@gmail.com> wrote:

I do have it (using app.yaml):

- url: /*
  filter: com.google.inject.servlet.GuiceFilter
  login: required

Hmmmm.  Please verify that GuiceFilter is in the stack trace produced by this exception.  Probably a good idea to post the trace here.

Jeff

Dominik Mayer

unread,
Feb 28, 2012, 9:28:54 AM2/28/12
to objectify...@googlegroups.com
It seems to have been my fault. Things look much better after I moved everything back to the static AbstractModule subclass. So I only need to figure out how to inject a static Ofy. I'll do more checks and post the result.

Dominik Mayer

unread,
Feb 28, 2012, 9:36:18 AM2/28/12
to objectify...@googlegroups.com
I think this is all related to the static Ofy. If I inject it, I get the OutOfScopeException, if I do not inject it, everything is starting fine (but I get a problem when I want to load my data from the client (static function via RequestFactory)).

Jeff Schnitzer

unread,
Feb 28, 2012, 9:37:32 AM2/28/12
to objectify...@googlegroups.com
On Tue, Feb 28, 2012 at 9:28 AM, Dominik Mayer <domini...@gmail.com> wrote:
It seems to have been my fault. Things look much better after I moved everything back to the static AbstractModule subclass. So I only need to figure out how to inject a static Ofy. I'll do more checks and post the result.

The phrase "static Ofy" does not sound good - Objectify instances are not thread safe and should not be used outside of the context of the current "session".

Jeff

Dominik Mayer

unread,
Feb 28, 2012, 9:41:24 AM2/28/12
to objectify...@googlegroups.com
The phrase "static Ofy" does not sound good - Objectify instances are not thread safe and should not be used outside of the context of the current "session".

So I guess this is the problem. How can I get an Ofy in a static context? Create the injector, create a new factory and run "begin()"? Or can I inject a static factory?

Because you asked:

[...]
Caused by: com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
at com.google.inject.servlet.GuiceFilter.getContext(GuiceFilter.java:135)
at com.google.inject.servlet.GuiceFilter.getRequest(GuiceFilter.java:121)
at com.google.inject.servlet.ServletScopes$1$1.get(ServletScopes.java:78)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40)
at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:53)
at com.google.inject.internal.InjectionRequestProcessor$StaticInjection$1.call(InjectionRequestProcessor.java:116)
at com.google.inject.internal.InjectionRequestProcessor$StaticInjection$1.call(InjectionRequestProcessor.java:110)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1024)
at com.google.inject.internal.InjectionRequestProcessor$StaticInjection.injectMembers(InjectionRequestProcessor.java:110)
at com.google.inject.internal.InjectionRequestProcessor.injectMembers(InjectionRequestProcessor.java:78)
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:170)
... 25 more
 

Jeff Schnitzer

unread,
Feb 28, 2012, 9:53:08 AM2/28/12
to objectify...@googlegroups.com
On Tue, Feb 28, 2012 at 9:41 AM, Dominik Mayer <domini...@gmail.com> wrote:
The phrase "static Ofy" does not sound good - Objectify instances are not thread safe and should not be used outside of the context of the current "session".

So I guess this is the problem. How can I get an Ofy in a static context? Create the injector, create a new factory and run "begin()"? Or can I inject a static factory?

First of all, I suggest reading the Guice docs.  It will clear up a lot of your confusion.  The docs are pretty good.

When you want access a narrowly scoped object (eg, request) from a broader scope (eg, application) you usually inject a Provider<Thing> rather than a Thing.  You could also, if you wanted, inject an OfyFactory (which should have application scope) and call begin() yourself.  But for consistency I would inject a Provider<Ofy>.

I'm guessing you already found requestStaticInjection().
 

Because you asked:


This stacktrace is incomplete, and doesn't show whether the GuiceFilter was executed as a filter during request execution. 

Jeff

Dominik Mayer

unread,
Feb 28, 2012, 10:48:36 AM2/28/12
to objectify...@googlegroups.com
First of all, I suggest reading the Guice docs.  It will clear up a lot of your confusion.  The docs are pretty good.

When you want access a narrowly scoped object (eg, request) from a broader scope (eg, application) you usually inject a Provider<Thing> rather than a Thing.  You could also, if you wanted, inject an OfyFactory (which should have application scope) and call begin() yourself.  But for consistency I would inject a Provider<Ofy>.

Ahhhh. Sorry, Jeff.... I'm using Provider<Thing> all the time. On the client, on the server... No idea why I didn't think about using it for the Ofy as well |-(.
 
I'm guessing you already found requestStaticInjection().

Yes, of course.

I'm looking into some other problems. I can reproduce the stack trace if you're still interested in it. (I only removed the upper part.)

Dominik Mayer

unread,
Feb 28, 2012, 12:00:08 PM2/28/12
to objectify...@googlegroups.com
These OutOfScopeExceptions were hiding other exceptions, mostly due to circular dependency. Once I removed "@RequestScoped" I could see and fix them. (I'm not injecting Ofys or UserServices anymore, only providers.) Now everything also works with "@RequestScoped".

And a stack trace that came up on the way:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
  at com.myapp.server.guice.GuiceServletConfig$ObjectifyModule.provideOfy(GuiceServletConfig.java:49)
  while locating com.myapp.server.db.Ofy
    for field at com.myapp.server.user.MyUserServiceImpl.ofy(MyUserServiceImpl.java:24)
  while locating com.myapp.server.user.MyUserServiceImpl
  while locating com.myapp.server.user.MyUserService
    for parameter 0 at com.myapp.server.channel.Channel.<init>(Channel.java:43)
  while locating com.myapp.server.channel.Channel
    for parameter 0 at com.myapp.server.channel.ChannelConnected.<init>(ChannelConnected.java:15)
  at com.myapp.server.channel.ChannelConnected.class(ChannelConnected.java:15)
  while locating com.myapp.server.channel.ChannelConnected

1 error
Feb 28, 2012 4:19:26 PM com.google.apphosting.utils.jetty.JettyLogger warn
Warnung: Failed startup of context com.google.appengine.tools.development.DevAppEngineWebAppContext@5ff7f9f{/,/home/dominik/Dokumente/workspace/myapp/war}
com.google.inject.ProvisionException: Guice provision errors:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
  at com.myapp.server.guice.GuiceServletConfig$ObjectifyModule.provideOfy(GuiceServletConfig.java:49)
  while locating com.myapp.server.db.Ofy
    for field at com.myapp.server.user.MyUserServiceImpl.ofy(MyUserServiceImpl.java:24)
  while locating com.myapp.server.user.MyUserServiceImpl
  while locating com.myapp.server.user.MyUserService
    for parameter 0 at com.myapp.server.channel.Channel.<init>(Channel.java:43)
  while locating com.myapp.server.channel.Channel
    for parameter 0 at com.myapp.server.channel.ChannelConnected.<init>(ChannelConnected.java:15)
  at com.myapp.server.channel.ChannelConnected.class(ChannelConnected.java:15)
  while locating com.myapp.server.channel.ChannelConnected

1 error
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:987)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1009)
at com.google.inject.servlet.ServletDefinition.init(ServletDefinition.java:108)
at com.google.inject.servlet.ManagedServletPipeline.init(ManagedServletPipeline.java:82)
at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102)
at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:172)
at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:97)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:662)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
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 org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:191)
at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:239)
at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:146)
at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:164)
at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113)
at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89)
Caused by: com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
at com.google.inject.servlet.GuiceFilter.getContext(GuiceFilter.java:135)
at com.google.inject.servlet.GuiceFilter.getRequest(GuiceFilter.java:121)
at com.google.inject.servlet.ServletScopes$1$1.get(ServletScopes.java:78)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40)
at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:53)
at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:110)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:94)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:54)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:84)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:84)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1031)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.Scopes$1$1.get(Scopes.java:65)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40)
at com.google.inject.internal.InjectorImpl$4$1.call(InjectorImpl.java:978)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1024)
at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:974)
... 25 more

Jeff Schnitzer

unread,
Feb 28, 2012, 12:15:14 PM2/28/12
to objectify...@googlegroups.com
I'm not a Guice expert, but the fact that this is being thrown from GuiceFilter.init() seems suspicious to me.  What does your web.xml look like?

Jeff

Dominik Mayer

unread,
Feb 28, 2012, 12:27:58 PM2/28/12
to objectify...@googlegroups.com
I'm not a Guice expert, but the fact that this is being thrown from GuiceFilter.init() seems suspicious to me.

I think I can live without the RequestScoped. Just wanted to tell you because I thought it was related to Objectify and Objectify 4 is not even a beta version...
 
What does your web.xml look like?

<!-- Generated from app.yaml. Do not edit. -->
<web-app version='2.5' xmlns='http://java.sun.com/xml/ns/javaee'>
  <security-constraint>
    <web-resource-collection>
      <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>
  <filter>
    <filter-name>com.google.inject.servlet.GuiceFilter</filter-name>

    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>com.google.inject.servlet.GuiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <security-constraint>
    <web-resource-collection>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>*</role-name>
    </auth-constraint>
  </security-constraint>
  <welcome-file-list>
    <welcome-file>myapp.html</welcome-file>
  </welcome-file-list>
  <listener>
    <listener-class>com.myapp.server.guice.GuiceServletConfig</listener-class>
  </listener>
</web-app>

But it really doesn't matter. If you're sure it's not related to Objectify I'll try to figure it out myself.

Jeff Schnitzer

unread,
Feb 28, 2012, 12:30:14 PM2/28/12
to objectify...@googlegroups.com
I'm 99% sure it's not related to Objectify.

Jeff

Ruslan V

unread,
Feb 28, 2012, 1:10:43 PM2/28/12
to Dominik Mayer
Dear Dominik,


Tuesday, February 28, 2012, 9:00:08 AM, you wrote:


These OutOfScopeExceptions were hiding other exceptions, mostly due to circular dependency. Once I removed "@RequestScoped" I could see and fix them. (I'm not injecting Ofys or UserServices anymore, only providers.) Now everything also works with "@RequestScoped".

And a stack trace that came up on the way:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
  at com.myapp.server.guice.GuiceServletConfig$ObjectifyModule.provideOfy(GuiceServletConfig.java:49)
  while locating com.myapp.server.db.Ofy
    for field at com.myapp.server.user.MyUserServiceImpl.ofy(MyUserServiceImpl.java:24)
  while locating com.myapp.server.user.MyUserServiceImpl
  while locating com.myapp.server.user.MyUserService
    for parameter 0 at com.myapp.server.channel.Channel.<init>(Channel.java:43)
  while locating com.myapp.server.channel.Channel
    for parameter 0 at com.myapp.server.channel.ChannelConnected.<init>(ChannelConnected.java:15)
  at com.myapp.server.channel.ChannelConnected.class(ChannelConnected.java:15)
  while locating com.myapp.server.channel.ChannelConnected


I suspect the problem is in the way you create instance of com.myapp.server.user.MyUserServiceImpl. In case you create it via "new MyUserServiceImpl" you need to create using injector.

I had similar problem with RequestFactory few days ago (spamming Jeff like crazy :).

/Ruslan
/Blue Industries (2012-02-28) Part 2 - Stefan Weise - Part 2 (Proton Radio)

Jeff Schnitzer

unread,
Jun 6, 2012, 1:51:11 PM6/6/12
to objectify...@googlegroups.com
Try it. I have found that Guice injection works on every
resteasy-instantiated object I've run across so far, so I suspect it
will work for resteasy interceptors.

Jeff

On Wed, Jun 6, 2012 at 10:32 AM, Miguel Andrade <jmand...@gmail.com> wrote:
> Hello, Jeff.
>
> Your project seems very interesting. Thank you. I'm using the same
> technologies: GAE, RESTeasy, Guice and Objectify 4.
>
> Are you familiar with Resteasy's interceptors? I'm wondering if I can inject
> something in an interceptor's contructor using your approach.
>
> Miguel.

Miguel Andrade

unread,
Jun 6, 2012, 1:54:44 PM6/6/12
to objectify...@googlegroups.com
Ok. I'll try and then post the results.

The way you integrate Guice with resteasy is a lot different than it is demonstrated on the Resteasy's documentation.

On your GuiceResteasyFilterDispatcher.java you have:

/**
* Use this as the Resteasy FilterDispatcher and it will be properly integrated with Guice.
* The normal Guice integration via servlet context listener seems to be incompatible with
* the "guice way".
*
* Note that you must define this filter in Guice so that it gets proper injection.
*
* @author Jeff Schnitzer
*/
Can you explain a bit why the normal Guice integration isn't compatible with the "Guice way"? What's the "Guice way"?

Thank you.

Jeff Schnitzer

unread,
Jun 6, 2012, 2:05:55 PM6/6/12
to objectify...@googlegroups.com
It's been a long time, but IIRC the resteasy-provided integration
basically conflicts with having your guice config as a servlet context
listener. The resteasy folks do it backwards, trying to instantiate
Guice from within Resteasy. It should go the other way around -
Resteasy instantiated within Guice.

It became pretty obvious to me that the author of that plugin really
wasn't very familiar with Guice. It also seemed to have been
abandoned. I haven't looked at that code within the last year, but I
doubt it's changed.

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 4:43:25 PM6/6/12
to objectify...@googlegroups.com
That totally makes sense. Thank you.

Now I'm just having problems while registering two of my entities, a class and a subclass of it.
In the OfyFactory.java constructor i do:

37. this.register(Consult.class);

38. this.register(GeneralConsult.class);


When I request an url, the following error comes out:

Caused by: java.lang.IllegalStateException: Unable to construct an instance of com.equilibrio.domain.consult.Consult; perhaps it has no suitable constructor?

at com.googlecode.objectify.impl.translate.ClassTranslator.<init>(ClassTranslator.java:44)

at com.googlecode.objectify.impl.translate.EntityClassTranslator.<init>(EntityClassTranslator.java:46)

at com.googlecode.objectify.impl.Transmog.<init>(Transmog.java:49)

at com.googlecode.objectify.impl.ConcreteEntityMetadata.<init>(ConcreteEntityMetadata.java:58)

at com.googlecode.objectify.impl.Registrar.register(Registrar.java:74)

at com.googlecode.objectify.ObjectifyFactory.register(ObjectifyFactory.java:177)

at com.equilibrio.infrastructure.dao.OfyFactory.<init>(OfyFactory.java:37)


Every other Entity registered very well.
I'm using lombok's @Data annotation in both the classes, just like every other entity in my project.

Very strange...

Jeff Schnitzer

unread,
Jun 6, 2012, 4:51:20 PM6/6/12
to objectify...@googlegroups.com
Entity classes need a default constructor. If you're using lombok's
@Data and final fields, there is no default constructor (and final
fields are a problem anyways). If that isn't the issue... try
constructing a Consult with the default constructor, that's what
Objectify tries to do by default.

If you've overridden ObjectifyFactory's construct() method to use
Guice to instantiate your class, it's possible some sort of injection
problem is the issue here. There should be relevant errors in the
logs.

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 6:45:30 PM6/6/12
to objectify...@googlegroups.com
I'm not using final fields.
Consult is an abstract class. It cannot be constructed.

Tried:

Consult c = new GeneralConsult();


It ran without a problem.

Abstract classes need to be registered too, right?
Anyway, I also tried removing this.register(Consult.class); and keeping just this.register(GeneralConsult.class); but it didn't work. The error complaining about consult class continues. The error is in the this.register(GeneralConsult.classline.

Also tried using @Getter and @Setter instead of @Data while declaring empty constructors explicitly in both classes. The error continues.

I've attached the log, from the server start until the error, after a request is made.

If you could help, I would be very grateful. Maybe there's some kind of problem with inheritance and the new Objectify?

Thank you!

Miguel
log.rtf

Jeff Schnitzer

unread,
Jun 6, 2012, 6:49:06 PM6/6/12
to objectify...@googlegroups.com
On Wed, Jun 6, 2012 at 3:45 PM, Miguel Andrade <jmand...@gmail.com> wrote:
> Consult is an abstract class. It cannot be constructed.
> Abstract classes need to be registered too, right?

Ah hah. So you have a polymorphic type hierarchy but the base class
is abstract? At the moment that isn't allowed. But it probably
should be. Would you file an issue against that?

For an immediate solution, make your class concrete and instead of
declaring abstract methods, make them throw
UnsupportedOperationException(). Not quite as typesafe but it will
get you over the hurdle for now.

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 6:59:46 PM6/6/12
to objectify...@googlegroups.com
It solved the problem!

I'll file this issue. It would be great to have this feature. Thank you!

Now, back to the original question about the interceptors.
Resteasy forces us to have an empty constructor (or default) in interceptors. It uses this constructor to create the interceptors during bootstrap (i think). The @Inject constructor never gets called. Also tried @Inject in the class field I want injected, but the variable is always null and never gets injected.

It won't be easy to inject the interceptors. Meanwhile I need a way of explicitly creating an Ofy instead of injecting it. How can I do this?

I'll investigate on the "injecting the interceptors" issue. If I find something I'll post it here.

Thanks again!

Miguel.

Miguel Andrade

unread,
Jun 6, 2012, 7:15:43 PM6/6/12
to objectify...@googlegroups.com
Actually, I forgot to bind the Interceptor.
I'm now invoking bind(BasicInterceptor.class); in the AbstractModule of GuiceConfig.java.
Now the following error appears during server startup (before any request is made):

WARNING: failed GuiceFilter: com.google.inject.ProvisionException: Guice provision errors:


1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.

  at com.equilibrio.utils.GuiceConfig$EquilibrioModule.provideOfy(GuiceConfig.java:65)

  while locating com.equilibrio.infrastructure.dao.Ofy

    for parameter 0 at com.equilibrio.services.interceptors.BasicInterceptor.<init>(BasicAuthInterceptor.java:38)

  while locating com.equilibrio.services.interceptors.BasicInterceptor



The log is right. We aren't currently inside an HTTP Servlet Request. I think this has to do with the @RequestScoped in the provideOfy method. What's your insight on this?

Jeff Schnitzer

unread,
Jun 6, 2012, 7:34:29 PM6/6/12
to objectify...@googlegroups.com
This sounds like a simple problem with Guice scopes - you're trying to
inject a @RequestScoped object in an object that has broader scope
(ie, @Singleton). The short answer is usually to inject a
Provider<Objectify> and use that.

A slightly longer answer is that I don't inject my Objectify instances
anymore, but rather use a thread local stack and a static method ofy()
that I can call from anywhere. This makes it easy to do data
operations inside entity classes - useful when you have polymorphic
behavior.

I plan to update the motomapia example with this pattern, although
it's not a great example since it doesn't use transactions.

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 7:47:00 PM6/6/12
to objectify...@googlegroups.com
I've tried the Provider approach. The resteasy providers scope is something that I don't understand.
To better illustrate my debugging, consider this:

public class BasicAuthInterceptor implements PreProcessInterceptor {


private Provider<Ofy> ofyProvider;

public BasicAuthInterceptor() {

System.out.println("hi");

}

@Inject

public BasicAuthInterceptor(Provider<Ofy> ofyProvider) {

this.ofyProvider = ofyProvider;

System.out.println("hi injected");

}


public ServerResponse preProcess(HttpRequest request, ResourceMethod arg1)

throws Failure, WebApplicationException {

Ofy ofy = this.ofyProvider.get();

//...


}


}


During startup the output was:

hi

hi

hi

hi

hi

hi

hi

hi injected

hi

hi

hi

hi

hi

hi

hi


Resteasy lacks documentation on this issue.

Miguel Andrade

unread,
Jun 6, 2012, 7:49:03 PM6/6/12
to objectify...@googlegroups.com
Also, when a request is made I get a null point exception because this.ofyProvider never gets injected, at least in the instance that executed in the request.

Jeff Schnitzer

unread,
Jun 6, 2012, 7:50:11 PM6/6/12
to objectify...@googlegroups.com
Make sure you're using javax.inject.Provider and not some other
resteasy or jax-rs Provider.

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 8:26:48 PM6/6/12
to objectify...@googlegroups.com
Yes, I am. The result is the same. I think that it is resteasy that is creating the interceptor and not Guice.

Jeff Schnitzer

unread,
Jun 6, 2012, 8:31:04 PM6/6/12
to objectify...@googlegroups.com
Maybe get rid of the default constructor and just keep the one with @Inject?

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 8:58:03 PM6/6/12
to objectify...@googlegroups.com
If I do that resteasy complains:

Unable to find a public constructor for interceptor class com.equilibrio.services.interceptors.BasicInterceptor

Jeff Schnitzer

unread,
Jun 6, 2012, 9:06:40 PM6/6/12
to objectify...@googlegroups.com
Hmmm... this is getting into the bowels of resteasy, a place I fear to
tread. If you have guice/resteasy set up the way it is in motomapia,
I'm afraid you've reached the end of my knowledge.

Resteasy and JAX-RS evolved completely separately from JSR299 CDI (and
of course Guice) so it duplicates a lot of the DI behavior, and does
so poorly. Honestly the interactions here are a bit of a trainwreck
and I'm not sure it will ever get worked out correctly - the Java web
platform will probably die off before anyone fixes it.

To workaround this immediately, you could use Guice static injection
and leave Resteasy's lame DI system intact.

Jeff

Miguel Andrade

unread,
Jun 6, 2012, 9:35:10 PM6/6/12
to objectify...@googlegroups.com
Ok, I think it is fixed now. :)
Thank you very much for your help, Jeff.

Resteasy definitely needs some improvements.

Hope our discussion helps someone.

Miguel.

Miguel Andrade

unread,
Jun 7, 2012, 1:35:13 PM6/7/12
to objectify...@googlegroups.com
Regarding your sample app, when I deployed to App Engine's servers, I got the following error:

Uncaught exception from servlet
java.lang.ExceptionInInitializerError
	at com.google.appengine.runtime.Request.process-945ee6eba1c86681(Request.java)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:33)
	at org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:132)
	at org.jboss.resteasy.spi.ResteasyProviderFactory.getProviderInstance(ResteasyProviderFactory.java:1039)
	at org.jboss.resteasy.spi.ResteasyProviderFactory.addMessageBodyReader(ResteasyProviderFactory.java:478)
	at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:757)
	at org.jboss.resteasy.plugins.providers.RegisterBuiltin.registerProviders(RegisterBuiltin.java:70)
	at org.jboss.resteasy.plugins.providers.RegisterBuiltin.register(RegisterBuiltin.java:31)
	at org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:211)
	at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.init(ServletContainerDispatcher.java:67)
	at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.init(FilterDispatcher.java:39)
	at com.equilibrio.utils.GuiceResteasyFilterDispatcher.init(GuiceResteasyFilterDispatcher.java:45)
	at com.google.inject.servlet.FilterDefinition.init(FilterDefinition.java:114)
	at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:98)
	at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:172)
	at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:97)
	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
	at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:662)
	at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
	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.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:449)
	at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:455)
	at com.google.tracing.TraceContext.runInContext(TraceContext.java:695)
	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:333)
	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:325)
	at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:453)
	at java.lang.Thread.run(Thread.java:679)
Caused by: java.lang.SecurityException: SHA1 digest error for org/bouncycastle/jce/provider/BouncyCastleProvider.class
	at com.google.appengine.runtime.Request.process-945ee6eba1c86681(Request.java)
	at sun.security.util.ManifestEntryVerifier.verify(ManifestEntryVerifier.java:210)
	at java.util.jar.JarVerifier.processEntry(JarVerifier.java:218)
	at java.util.jar.JarVerifier.update(JarVerifier.java:205)
	at java.util.jar.JarVerifier$VerifierStream.read(JarVerifier.java:428)
	at sun.misc.Resource.getBytes(Resource.java:124)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:273)
	at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
	at org.jboss.resteasy.security.smime.EnvelopedReader.<clinit>(EnvelopedReader.java:35)
	... 32 more

It happened during the startup of GuiceResteasyFilterDispatcher.java:45.
In the local server everything runs fine.

Did you experience this problem, Jeff?

Miguel Andrade

unread,
Jun 7, 2012, 1:53:50 PM6/7/12
to objectify...@googlegroups.com
Ok, I solved it. BouncyCastle isn't allowed in GAE.
I just removed the resteasy crypto jar and it all went fine. :)
Reply all
Reply to author
Forward
0 new messages