How do I use Kotlin with Google App Engine?


#1

I've been trying to set up a Google App Engine with IDEA (I'm an IDEA newbie, but I've got a decade of experience with Eclipse).

With signfiicant help from Jetbrains support, I’ve now got a test GAE project set up, and I can run it and see the output of a simple servlet in my web browser.

So I deleted this simple servlet and created a Kotlin file containing a class with the same name in the same package, also subclassing HttpServlet, with a doGet() method.  I added the kotlin-runtime.jar to the WEB-INF/lib folder, which is where libraries are supposed to go in Google App Engine.

Unfortunately, when I try to run this now I get a ClassNotFoundException - it can’t find the Kotlin class with the servlet.

What am I doing wrong?

Ian.


#2

I have no experience with GAE, but I'd do following:

  1. Use java

  2. Get any external java library (like commons-lang)

  3. Place library in WEB-INF/lib

  4. Write simple servlet that calls any method of that library in doGet()

If all this does not work, then problem is not in Kotlin. If it works, then probably something’s wrong with Kotlin, we need to think.


#3

I wrote a Java servlet that accessed the AbstractIterator class in the kotlin-runtime.jar library, and it worked fine.  It seems that the issue is that the Kotlin class isn't being compiled, or the resultant .class files are not being put in the same place as the Java files.


#4

Please share the project somewhere: all sources, all binaries (including you've compiled) and show full stack trace of error. Maybe I could help you find, what's wrong.


#5

Per your request I've attached the project, although note that it assumes that the Google App Engine SDK is here:

  /Users/ian/java-libs/appengine-java-sdk-1.6.4.1

Here is the exception I get when I try to run it (note that it seems to work fine when I use a Java file that has the same class name, package, and functionality):

Apr 7, 2012 7:21:46 PM com.google.apphosting.utils.jetty.JettyLogger warn WARNING: EXCEPTION java.lang.ClassNotFoundException: testpack.TestServlet at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass(IsolatedAppClassLoader.java:176) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) at org.mortbay.util.Loader.loadClass(Loader.java:91) at org.mortbay.util.Loader.loadClass(Loader.java:71) at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:73) at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:242) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685) 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:196) 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:189) at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:128) at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:104) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)



gaetest1.zip (6.15 MB)

#6

According to stack trace problem is not with kotlin runtime, app engine cannot find testpack.TestServlet.

How do you start your application?

If you just execute something like

…/appengine-java-sdk-1.6.4.1/bin/dev_appserver.sh web

it should not work, because app engine looks for classes in web/WEB-INF/lib and web/WEB-INF/classes and testpack.TestServlet is not in these folders.

I did

cp -r out/production/gaetest1 web/WEB-INF/classes

After that servlet works fine.


#7

Yes, I can confirm that manually copying the class files across and running GAE from the command line as you suggest does work - yay progress! ;-)

But the question is: why isn’t this working from within IDEA - since it was working with Java?  To start it I was just hitting the green “Play” button in IDEA (“Run ‘AppEngine Dev’”).

This seems to work fine when the source file is Java, it copies the compiled class files over to WEB-INF/classes as it should (I think it is configured in Project Structure -> Artifacts), so why wouldn’t it be doing this for a Kotlin source file?


#8

It seems to be a bug somewhere between IDEA's build/deploy infrastructure and Kotlin. Please, feel free to file an issue in our bug tracker. Thanks