DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more
  1. DZone
  2. Coding
  3. Frameworks
  4. Using Spring’s Java Configuration on Google App Engine

Using Spring’s Java Configuration on Google App Engine

Andrew Phillips user avatar by
Andrew Phillips
·
Jan. 18, 10 · Interview
Like (0)
Save
Tweet
Share
9.85K Views

Join the DZone community and get the full member experience.

Join For Free

recently, i put together a spring demonstration for jclouds , the java cloud library. this quickly turned into unexpected multi-dimensional experiment in integrating guice , google app engine and spring , but after much trial-and-error i finally came across a configuration that does the trick - or at least works 1 as well as seems possible on gae.

the tweetstore demo

tweetstore is a simple web application that demonstrates jclouds' cloud capabilities. it queries twitter for mentions of the user's account and creates a "backup" of this priceless record of your contemporary image in three cloud stores: amazon s3 , microsoft's azure and rackspace . nothing less than double redundancy is good enough for your popularity!

the original tweetstore application uses guice for dependency injection and request mapping. in order to make it as easy as possible to compare the spring version to the original, i decided to try to similarly do as much in java code as possible. a perfect opportunity for me to get my hands dirty with spring 3.0's support for java configuration .

bootstrapping spring's java configuration

the first, relatively straight-forward step was to convert the guice servlet module into an equivalent spring @configuration :

@configuration
public class springservletconfig extends loggingconfig implements servletconfigaware {
private servletconfig servletconfig;
...

@postconstruct
public void initialize() {
...
}

@bean
public storetweetscontroller storetweetscontroller() {
storetweetscontroller controller = new storetweetscontroller(providertypetoblobstoremap,
container, twitterclient);
injectservletconfig(controller);
return controller;
}

@bean
public addtweetscontroller addtweetscontroller() {
addtweetscontroller controller = new addtweetscontroller(providertypetoblobstoremap,
servicetostoredtweetstatuses());
injectservletconfig(controller);
return controller;
}

private void injectservletconfig(servlet servlet) {
try {
servlet.init(checknotnull(servletconfig));
} catch (servletexception exception) {
throw new beancreationexception("unable to instantiate " + servlet, exception);
}
}

@bean
servicetostoredtweetstatuses servicetostoredtweetstatuses() {
return new servicetostoredtweetstatuses(providertypetoblobstoremap, container);
}

@bean
public handlermapping handlermapping() {
simpleurlhandlermapping mapping = new simpleurlhandlermapping();
map<string, object> urlmap = maps.newhashmapwithexpectedsize(2);
urlmap.put("/store/*", storetweetscontroller());
urlmap.put("/tweets/*", addtweetscontroller());
mapping.seturlmap(urlmap);
/*
* "/store" and "/tweets" are part of the servlet mapping and thus stripped
* by the mapping if using default settings.
*/
mapping.setalwaysusefullpath(true);
return mapping;
}

@bean
public handleradapter servlethandleradapter() {
return new simpleservlethandleradapter();
}

...
}

being servletconfigaware isn't exactly spring best practice but then the chosen aim was to stay as close as possible to the original set-up rather than building a spring reference application.

hooking spring into the gae startup was the next step. the spring reference example was my first attempt:

<web-app>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class>
<!-- configure dispatcherservlet to use javaconfigwebapplicationcontext
instead of the default xmlwebapplicationcontext -->
<init-param>
<param-name>contextclass</param-name>
<param-value>org.springframework.web.context.support.annotationconfigwebapplicationcontext</param-value>
</init-param>
<init-param>
<param-name>contextconfiglocation</param-name>
<param-value>org.jclouds.demo.tweetstore.config.springservletconfig</param-value>
</init-param>
</servlet>

<servlet-mapping>
...
</web-app>

unfortunately, this unceremonially blew up in my face with a security violation: annotationconfigwebapplicationcontext (and all spring contexts that register a commonannotationbeanpostprocessor ) attempts to load javax.annotation.resource to determine support for jsr-250 , and that class, unlike others in the javax.annotation package, happens to be missing from the gae whitelist.

it ain't over until the app engine sings

moving back to a standard -servlet.xml file gets rid of the @resource problem, but i was still left with an exception caused by guice, which jclouds uses internally for dependency injection. i later discovered that the exception is relatively harmless and can be ignored 2 . but of course no developer likes exceptions - however harmless - in the boot logs, so i wondered whether executing this call earlier in the boot sequence might resolve the problem.

so i moved the offending call from the servlet to the application context, guessing that the contextloaderlistener might have more permissions than a servlet:

<web-app>
<!-- can't use java sconfiguration due to gae's security restrictions -->
<context-param>
<param-name>contextconfiglocation</param-name>
<param-value>/web-inf/tweetstorecontext.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.contextloaderlistener</listener-class>
</listener>

<servlet>
...

and it worked! or rather, it worked on the java development server , the app engine "simulator" provided with the sdk which is intended for development testing. but it didn't work on app engine itself 3 .
a word of caution, therefore: test on the "real" app engine before concluding that something works, especially if it's related to security restrictions!

salvaging some @annotationconfig

by this time i knew that i wasn't going to get away without writing at least a bit of spring xml, but i was still trying to stick to java as much as possible. after plenty of digging around in the spring sources and a bit of experimentation, i discovered that, of the bean post processors currently registered by <context:annotation-config/> 4 that i was interested in, only the commonannotationbeanpostprocessor actually causes a problem. in fact, you can even use its immediate superclass, initdestroyannotationbeanpostprocessor, which provides the @postconstruct and @predestroy support i was looking for:

<beans xmlns="...>
<!-- the usual <context:annotation-config/> can't be used because the
commonannotationbeanpostprocessor causes a security exception in gae when it
tries to load javax.annotation.resource -->
<bean class="org.springframework.beans.factory.annotation.autowiredannotationbeanpostprocessor" />
<bean class="org.springframework.context.annotation.configurationclasspostprocessor" />
<bean class="org.springframework.beans.factory.annotation.initdestroyannotationbeanpostprocessor">
<property name="initannotationtype" value="javax.annotation.postconstruct" />
<property name="destroyannotationtype" value="javax.annotation.predestroy" />
</bean>
<bean class="org.jclouds.demo.tweetstore.config.springservletconfig" />
</beans>

so if you can live without @resource, it seems that you can get away with most of spring's annotation-driven configuration on the gae.

debugging the java development server

the gae sdk starts the java development server using a platform-independent launcher called kickstart, which is quite easy to integrate into your test suite.
unfortunately, kickstart doesn't start the server in a new thread , but in a completely separate process , so attaching a debugger from your ide is, well, tricky.
luckily kickstart accepts jvm_flag arguments , as outlined in the javadocs 5 :

at present, the only valid option to kickstart itself is:
--jvm_flag=<vm_arg>
passes <vm_arg> as a jvm argument for the child jvm. may be repeated

here you can add the standard jvm debugging parameters .

footnotes
  1. well, actually it's running into a timeout at the time of writing, but that's not related to the spring config. really ;-)
  2. which is to say that it doesn't interrupt the bootstrapping process (it occurs in a separate thread), and your application will run fine. here it is:


    com.google.inject.internal.finalizablereferencequeue : failed to start reference finalizer thread. reference cleanup will only occur when new references are created.
    java.lang.reflect.invocationtargetexception
    ...
    at com.google.inject.internal.injectorbuilder.initializestatically(injectorbuilder.java:134)
    at com.google.inject.internal.injectorbuilder.build(injectorbuilder.java:108)
    at com.google.inject.guice.createinjector(guice.java:93)
    at com.google.inject.guice.createinjector(guice.java:70)

  3. i suspect this has something to do with how and when the security manager is installed in the dev server, but haven't investigated this in any detail.
  4. the spring docs don't mention configurationclasspostprocessor, for some reason, but according to its javadoc it is "registered by default when using <context:annotation-config/> or <context:component-scan/>."
  5. which don't appear to be available online, for some reason.

from http://blog.xebia.com

app Java (programming language) Google App Engine Engine Spring Framework Google (verb)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Automated Testing With Jasmine Framework and Selenium
  • Frontend Troubleshooting Using OpenTelemetry
  • Readability in the Test: Exploring the JUnitParams
  • A Deep Dive Into AIOps and MLOps

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: