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
Jeff
--
We are the 20%
Here it is:
Jeff
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)
[...]
Have you done a clean build?
If you have built against Objectify then you shouldn't have a linker issue.Any chance you have multiple objectify jars on your classpath?
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.
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?
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.
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.
Tried proxying com.mitado.server.db.OfyFactory to support a circular dependency, but it is not an interface
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>
- url: /*
filter: com.google.inject.servlet.GuiceFilter
login: required
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...
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
I do have it (using app.yaml):- url: /*
filter: com.google.inject.servlet.GuiceFilter
login: required
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".
[...]
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
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:
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().
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?
<!-- 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>
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 |
/*** 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*/
37. this.register(Consult.class);
38. this.register(GeneralConsult.class);
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)
Consult c = new GeneralConsult();
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
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();
//...
}
}
hi
hi
hi
hi
hi
hi
hi
hi injected
hi
hi
hi
hi
hi
hi
hi
Unable to find a public constructor for interceptor class com.equilibrio.services.interceptors.BasicInterceptor
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