Ardent Lord

That's me

Blog

Spring 3.0 on Google App Engine

Posted by Idris at 01:27 PM on April 19, 2009

-- Note: If you just want the nitty gritty without my blabbing, ignore the first paragraph --

So last week I got the inspiration to try out Google App Engine after reading about the new Java support. I searched around to find some resources on getting Spring running on App Engine, but the resources were surprisingly scarce. Google points you to their "autoshoppe" example, which is a little incomplete in terms of setup and what libraries you need. Ironically, Spring Source's post about App Engine was talking about using Groovy, not Spring. Finally I found a blog entry by Sikeh. So I got a nice Hello World up and running on Spring 2, thanks to Sikeh, but I wasn't satisfied yet. I wanted Spring 3. Spring 2 is so... 2008. So I started bringing in some Spring 3 (M2) jars, played around a little more, did some Googling, and finally got Spring 3 up and running.

Here's how you'll need to setup the directory structure:

  1. Setup a Google App Engine project (I used the Eclipse plugin)
  2. Download Spring 3.0.0.M2 (or the latest version)
  3. Copy the following jar files from Spring into the /war/WEB-INF/lib directory:
    org.springframework.beans-3.0.0.M2.jar
    org.springframework.context-3.0.0.M2.jar
    org.springframework.core-3.0.0.M2.jar
    org.springframework.expression-3.0.0.M2.jar
    org.springframework.web-3.0.0.M2.jar
    org.springframework.web.servlet-3.0.0.M2.jar
  4. Spring also depends on the following jars, which you can search for around the internet, or download from my Spring Example git repository:
    antlr-3.0.1.jar
    asm-2.1.jar
    asm-commons-2.1.jar
    commons-logging-1.1.1.jar
  5. Finally, you'll need to rename the commons-logging-1.1.1 jar to something else, like commons-logging.jar (thanks to Martin for this tip!)

Next, you'll need to configure your web.xml for Spring. In web.xml I added a catch-all mapping to my Spring dispatcher:

<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>

WARNING: If you use a catch-all (/*) url-pattern, the application will not work in development mode (locally), but will work on the AppEngine server. I believe this is a known bug.

For my dispatcher-servlet.xml: (also in /war/WEB-INF/)

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="example.controllers" /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp" /> </beans>

You obviously want to change the base-package to whatever package you want. I use the InternalResourceViewResolver, and put all my views in /WEB-INF/views/. Finally, here's my (uninteresting) applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> </beans>

Now we're all done with setup! Just create a controller and a view. I made a simple hello.jsp view that outputs the request parameter "name". Here's the controller:

package example.controllers.hello; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @RequestMapping("/hello/{name}") public String hello(@PathVariable String name, Model model) { model.addAttribute("name", name); return "hello/hello"; } }

So there you have it. Spring up and running on Google App Engine. You can see it in action at http://springexample.appspot.com/, or you can get the source at http://github.com/idris/spring-example-gae/. For now, this is all just a Hello Wold. I'll post more functionality later... Feel free to suggest topics in the comments!

Categories: None

Post a Comment

Oops

  • Oops, you forgot something.
You must be a member to comment on this page. Sign In or Register

11 Comments

Reply cheolho
10:09 PM on April 22, 2009
WARNING: If you use a catch-all (/*) - I got this working in hosted mode but found other issues with Jetty. Can I ask what happens when you try to use this from your demo ? Try enabling logging for spring, and see what dispatcher output is. I will address this in my next blog, and show what i had to do to get it working. But from what you have in your demo .. this should work.
Reply Idris
10:23 PM on April 22, 2009
cheolho says...
WARNING: If you use a catch-all (/*) - I got this working in hosted mode but found other issues with Jetty. Can I ask what happens when you try to use this from your demo ? Try enabling logging for spring, and see what dispatcher output is. I will address this in my next blog, and show what i had to do to get it working. But from what you have in your demo .. this should work.


Sure, it works fine on the appserver ( http://springexample.appspot.com ), but when I run it locally, everything is a 404. The static files give a 404, and my controller yields a strange 404 for RequestURI=/WEB-INF/views/hello/hello.jsp
Reply Idris
10:25 PM on April 22, 2009
Oh, and the Spring error messages:
WARNING: No mapping found for HTTP request with URI [ /index.htm ] in DispatcherServlet with name 'dispatcher'
Apr 22, 2009 10:22:12 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound

Apr 22, 2009 10:24:12 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [ /WEB-INF/views/hello/hello.jsp ] in DispatcherServlet with name 'dispatcher'
Reply cheolho
10:26 PM on April 22, 2009
Yes this is the same issue I was having. If for example you view the PetShop Clinic in spring they use the path default /static/* meant for static files, images, js, css.. etc. This will work on tomcat but jetty is no good. Ill write up the solution and let you know.
Reply Oleg
04:35 PM on April 28, 2009
To solve the mapping issue try mapping filter to /* path and explicitly dispatch from filter to servlet cfg.getServletContext().getNamedDispatcher("dispatcher").forward(
req, resp); Don't forget to remove servlet-mapping from web.xml as well.
Reply ramesh
05:28 AM on May 27, 2009
Hi, I have upgraded my project with spring.3.0.0M2 and I am getting the below error. Can u please guide me to solve this error? Even I have spring.core package in my dependancy.
java.lang.NoClassDefFoundError: org/springframework/core/type/classreading/AnnotationMetadataRead
ingVisitor
Reply Ildar
09:47 AM on June 10, 2009
Idris says...
Oh, and the Spring error messages:
WARNING: No mapping found for HTTP request with URI [ /index.htm ] in DispatcherServlet with name 'dispatcher'
Apr 22, 2009 10:22:12 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound

Apr 22, 2009 10:24:12 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [ /WEB-INF/views/hello/hello.jsp ] in DispatcherServlet with name 'dispatcher'


I've use IntelliJIdea, run you project and get
06-10 06:43AM 58.535
javax.servlet.ServletContext log: Initializing Spring FrameworkServlet 'dispatcher'
W 06-10 06:44AM 00.138
org.springframework.web.servlet.DispatcherServlet noHandlerFound: No mapping found for HTTP request with URI [/] in DispatcherServlet with name 'dispatcher'

something incorect with web.xml?
Reply Max Harper
09:09 AM on June 18, 2009
To fix the dispatcher problem, see http://blog.newsplore.com/?p=773

Short answer: get rid of the asterisk in the /* url-pattern. This works locally; not confirmed on a live AppEngine instance yet.

BTW - thanks for the great post.
Reply cheolho
06:40 PM on June 18, 2009
concerning static mapping, on GAE hosted mode, and dev , you can check out my solution here - http://bit.ly/y6xf7 .. i created my own servlet to serve content with links to support why I did it. Also wrote about solution for json view.
Reply Dan
05:34 PM on August 14, 2009
Thanks for the post.

How did you choose which jars to include? There are many more in the package.
Reply Idris
08:24 PM on August 14, 2009
@Dan: Choosing the jars was the hard part.. Using all the jars didn't work, so I started with core and kept adding necessary jars until it compiled and worked. In other words, the work is already cut out for you

Welcome

Follow Me

Recent Blog Entries

Blogroll

Featured Products