Weld CDI on Google App Engine: Injection in servlet not happening - google-app-engine

This is my first time working with GAE and I'm trying to get CDI working. Long story short: The #Inject field in my servlet is not getting injected (it's always null).
I'm working in Eclipse and debug the application on the local test server included in the GAE SDK (which is started by Eclipse as well). When I access the servlet on localhost, I get a null-pointer exception for someService. I've also output the value of someService to verify it is really null, which it is.
Edit: When I added a #Named("skldjfx") qualifier to the injection point, Weld complained the dependency is unsatisfied (in the validation phase), so that's a good sign. However, the field is still always null.
Servlet:
public class BlogServlet extends HttpServlet {
#Inject private SomeService someService;
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println("Hello. " + someService.getSomeValue());
// \
// always null
}
}
SomeService class:
#ApplicationScoped
public class SomeService {
private String someValue = "some value";
public String getSomeValue() {
return someValue;
}
}
I've configured Weld's Listener in web.xml:
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
The listener is properly loaded because it logs its initialization message: org.jboss.weld.environment.servlet.Listener contextInitialized.
I've included (an empty) beans.xml in both war/WEB-INF and war/META-INF. I also tried it without META-INF. Maybe beans.xml isn't processed? Other contents in the WEB-INF folder (such as web.xml) are processed properly.
How can I verify if beans.xml is processed and/or fix SomeService not getting injected?

It looks like it's not possible to use CDI with GAE, because GAE's Jetty fork ignores jetty-web.xml, which is needed to specify the BeanManager. See this link and this link. Really strange GAE is not supporting the use of CDI.
Note that these links are really old, but so far I haven't found any evidence to the contrary.
Anyway, my next step will be to use Google's own dependency injection framework Guice. Using it with GAE is described here. I'd prefer CDI though.

Related

GAE : java.lang.NoClassDefFoundError: com/google/appengine/api/blobstore/BlobstoreServiceFactory

Kindly help me with this. I am using blob store for saving images and it is working perfectly fine on my local environment. But when I deploy the same code the cloud it is throwing me the exception : java.lang.NoClassDefFoundError: com/google/appengine/api/blobstore/BlobstoreServiceFactory
I am using GAE 1.8.4
Most likely, appengine-api.jar is missing from your war/WEB-INF/lib/ folder.
If you use Eclipse, click on the Problems tab. You may see a warning saying that this jar is not available on a server. Right click on this warning, select QuickFix, select "Copy..." option. Or copy this jar to this directory manually.
In my case the required jar was inside the WEB-INF/lib folder but the error was still occuring... I found that this error was occuring because Jetty 9 was not done yet with class loading startup process while one of my initialization class was requiring BlobstoreService:
public class InitializeAppContextListener implements ServletContextListener {
private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
So I had to postpone instance variable initialization once context is fully loaded as follow:
public class InitializeAppContextListener implements ServletContextListener {
private BlobstoreService blobstoreService;
public void contextInitialized(ServletContextEvent event) {
blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
Then the webapp was able to start normally again. This new behavior appeared after we had upgraded from servlet-api 2.5 to 3.1 with JDK 1.8...

AspectJ advice not being detected in Spring application

I had an existing WAR with the following Spring (4.0.6.RELEASE) configuration:
<beans>
<context:annotation-config/>
<context:component-scan base-package="org.example"/>
</beans>
To this application I added the following annotation interface (copied verbatim):
package org.example;
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD })
public #interface Logged {}
the following Aspect class (copied verbatim as well):
package org.example;
#Aspect
#Component
public class LoggingAspect
{
#Before("#annotation(Logged)")
public void before()
{
System.out.println("LoggingAspect.before()");
}
}
and the following batch processing class (copied verbatim):
package org.example;
#Component
public class Batch
{
#Logged
#Scheduled(fixedDelay = 100)
public void execute()
{
System.out.println("Batch.execute()");
}
}
The Spring configuration was then changed to:
<beans>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:annotation-config/>
<context:component-scan base-package="org.example"/>
<task:annotation-driven executor="executor" scheduler="scheduler"/>
<task:executor id="executor" pool-size="5"/>
<task:scheduler id="scheduler" pool-size="5"/>
</beans>
I was expecting to see the following messages on the console:
LoggingAspect.before()
Batch.execute()
However, I only see the second of these messages (that is, the aspect code is not being called).
I took out this code to a sample application and interestingly the two messages appear just fine in the sample app. I then compared every single file in the actual application with the sample and ensured that everything is exactly the same, including the class and file names. Yet, the aspect does not work in the actual application.
Upon turning on debug level logging in both applications, the sample application shows the following log message:
DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void org.example.LoggingAspect.before()
but the actual application does not have this log message. This seems to indicate that the sample app detects the aspect method but the actual app does not. Both use the same Spring and AspectJ versions (4.0.6.RELEASE and 1.8.1 respectively). There are no errors in either log.
Spring instantiates LoggingAspect in both cases (gleaned from the logs).
I have also checked various JAR dependencies for the two apps and everything is the same, except that the actual app uses Spring ORM, Hibernate and EHCACHE JARs which the sample app does not.
Any pointers on what else should be checked will be useful.
Despite debugging the application for months, upgrading and degrading various Spring and AspectJ versions, the problem could not be resolved. Funnily enough, a sample application created out of the affected classes did not show any problems.
I had to finally circumvent the problem by specifying the aspect in the Spring configuration. The line:
<aop:aspectj-autoproxy proxy-target-class="true"/>
had to be changed to:
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="loggingAspect"/>
</aop:aspectj-autoproxy>
In this case loggingAspect is the default bean name assigned by the Spring framework to the instance of the bean class LoggingAspect. If the bean name is set to a different value, that value must be used with <aop:include />.

HttpServlet is a restricted class. Please see the Google App Engine

I am getting the following error when running a basic servlet on Eclipse Kepler (Windows 7) with GAE SDK 1.9.3 and Java 7:
java.lang.NoClassDefFoundError: javax.servlet.http.HttpServlet is a restricted class.
Please see the Google App Engine developer's guide for more details.
To reproduce:
install Java 7 SDK
install Kepler
install the GAE Eclipse plugin
create a GAE web project
implement the init method of a basic servlet and set load-on-startup to 1 in web.xml
then run the web application
I tried on 2 machines and I got the same error.
Create a servlet by extending HttpServlet, then Override doPost() and doGet() methods in your servlets. For example:
public class FileServlet extends HttpServlet {
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// do something
}
Well, I found what was wrong and it was my mistake. Sorry. When I installed Java 7, I specified a different directory for the JDK and the JRE, which is fine, except that I gave the same location twice and the files got mixed up. My GAE issue was a side effect.

Cannot inject TimerService

I have an application in JBoss AS 7.1.1 and would like to use the TimerService. I inject it thusly:
#Resource
private TimerService timerService;
This results in the following error when accessing a page in the application:
16:08:30,471 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/c3e].[Faces Servlet]] (http--127.0.0.1-8080-2) Servlet.service() for servlet Faces Servlet threw exception: javax.naming.NameNotFoundException: env/myapp.mypackage.MyClass/timerService -- service jboss.naming.context.java.module.myapp.myapp.env."com.dpdhl.cac.c3e.etl.beans.Resources".timerService
I have tried several other methods, including injecting the SessionContext or using lookup() on an InitialContext to obtain the SessionContext, but they all run into essentially the same problem.
What am I missing here?
Problem solved: the bean into which I inject TimerService must be an EJB, not just a CDI bean as it was. I added
#Singleton
to the bean's declaration and it works now.

How can I configure the JAX-RS base path in TomEE+?

I have a WAR with some JAX-RS services, deployed into TomEE Plus. Given a service annotated with #Path("myservice"), TomEE+ publishes it to localhost:8080/mywebapp/myservice.
However, that also makes accessing a JSP at localhost:8080/mywebapp/index.jsp impossible - JAXRSInInterceptor complains that No root resource matching request path has been found, Relative Path: /index.jsp.
So I would like to configure a path prefix api to all services, which changes the myservice URL to localhost:8080/mywebapp/api/myservice. Doing so would be trivial if I had configured CXF on my own (with or without Spring), because I could simply change the URL pattern of the CXF Servlet - but I am relying on the default settings where I don't configure anything besides the annotations. So how do I do that in this case?
Note that I don't want to alter the #Path annotations to include the prefix, because that does not fix the issue with the JSP.
Create an extension of javax.ws.rs.core.Application and annotate it with #ApplicationPath where value would be api in your case:
#ApplicationPath("/api")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
// register root resource
classes.add(MyServiceResource.class);
return classes;
}
}
This way a Servlet 3 container would find your application and map your resource to /mywebapp/api/myservice while making your web resources (.jsp) available at /mywebapp.
TomEE trunk supports these configurations: cxf.jaxrs.staticSubresourceResolution & cxf.jaxrs.static-resources-list
but the #ApplicationPath is the more relevant solution IMO
Using -Dopenejb.webservice.old-deployment=true can help too in some cases

Resources