Enterprise Java

Spring MVC and REST at Google App Engine

Some time ago I wrote about how to implement your Restful Web API using Spring MVC. Read my previous post to know about it.

In that post it was developed a simple Rest example. For testing the application, file was copied into a web server (Tomcat for example), and then accessing to http://localhost:8080/RestServer/characters/1 information of character 1 was returned.

In current post I am going to explain how to transform that application to a Google App Engine and be deployed into Google’s infrastructure using Maven. Of course in this case we are going to deploy a Rest Spring MVC application, but same approach can be used for migrating a Spring MVC web application (or any other application developed with other web framework) to GAE.

First of all, obviously you should create a Google Account and register a new application (remember the name because will be used in next step). After that you can start the migration.

Three changes are required, create appengine-web.xml defining application name; add server tag to settings.xml with Google account information, and modify pom.xml for adding GAE plugin and its dependencies.

Let’s start with appengine-web.xml. This file is used by GAE to configure application and is created into WEB-INF directory (at same level of web.xml).

01
02
03
04
05
06
07
08
09
10
11
12
<?xml version="1.0" encoding="utf-8"?>
    <application>alexsotoblog</application>
    <version>1</version>
 
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
    </system-properties>
    <precompilation-enabled>false</precompilation-enabled>
    <sessions-enabled>true</sessions-enabled>
</appengine-web-app>

The most important field is application tag. This tag contains the name of our application (defined when you register a new Google Application).

Other tags are version, system properties and environment variables, and misc configuration like if you want a precompilation to enhance performance or if your application requires sessions.

And your project should not be modified anymore, now only Maven files will be touched.

In settings.xml, account information should be added:

01
02
03
04
05
06
07
08
09
10
11
12
13
  <localRepository>/media/share/maven_repo</localRepository>
  <servers>
        <server>
            <id>appengine.google.com</id>
            <username>my_account@gmail.com</username>
            <password>my_password</password>
        </server>
 
    </servers>
   
</settings>

See that it is as easy as registering any other server in Maven.

And finally the most tedious part, modifying pom.xml.

First thing is adding new properties:

1
2
3
4
5
6
7
<gae.home>/media/share/maven_repo/com/google/appengine/appengine-java-sdk/1.5.5/appengine-java-sdk-1.5.5</gae.home>
<gaeApplicationName>alexsotoblog</gaeApplicationName>
<gaePluginVersion>0.9.0</gaePluginVersion>
<gae.version>1.5.5</gae.version>
 
<!-- Upload to http://test.latest.<applicationName>.appspot.com by default -->
<gae.application.version>test</gae.application.version>

At first line we are defining Appengine Java SDK location. If you have already installed then insert location in this tag, if not, copy same location of this pom and simply change maven repository directory, in my case /media/share/maven_repo, to yours. Typically your Maven repository location will be /home/user/.m2/repositories. Maven will download SDK for you at deploy time.

Next step is adding Maven GAE repository.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<repositories>
 <repository>
  <id>maven-gae-plugin-repo</id>
  <name>maven-gae-plugin repository</name>
 </repository>
</repositories>
 
<pluginRepositories>
 <pluginRepository>
  <id>maven-gae-plugin-repo</id>
  <name>Maven Google App Engine Repository</name>
 </pluginRepository>
</pluginRepositories>

Because our project is dummy project, Datanucleus are not used. In case of more complex projects, that database access is required using, for example JDO, next dependencies should be added:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<dependency>
 <groupId>javax.jdo</groupId>
 <artifactId>jdo2-api</artifactId>
 <version>2.3-eb</version>
 <exclusions>
  <exclusion>
   <groupId>javax.transaction</groupId>
   <artifactId>transaction-api</artifactId>
  </exclusion>
 </exclusions>
</dependency>
 
<dependency>
 <groupId>com.google.appengine.orm</groupId>
 <artifactId>datanucleus-appengine</artifactId>
 <version>1.0.6.final</version>
</dependency>
 
<dependency>
 <groupId>org.datanucleus</groupId>
 <artifactId>datanucleus-core</artifactId>
 <version>1.1.5</version>
 <scope>runtime</scope>
 <exclusions>
  <exclusion>
   <groupId>javax.transaction</groupId>
   <artifactId>transaction-api</artifactId>
  </exclusion>
 </exclusions>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>geronimo-jta_1.1_spec</artifactId>
 <version>1.1.1</version>
 <scope>runtime</scope>
</dependency>
 
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>geronimo-jpa_3.0_spec</artifactId>
 <version>1.1.1</version>
 <scope>runtime</scope>
</dependency>

And in case you are using Datanucleus, maven-datanucleus-plugin should be registered. Take care to configure it properly depending on your project.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<plugin>
            <groupId>org.datanucleus</groupId>
            <artifactId>maven-datanucleus-plugin</artifactId>
            <version>1.1.4</version>
            <configuration>
                <!--
                    Make sure this path contains your persistent
                    classes!
                -->
                <mappingIncludes>**/model/*.class</mappingIncludes>
                <verbose>true</verbose>
                <enhancerName>ASM</enhancerName>
                <api>JDO</api>
            </configuration>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>enhance</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.datanucleus</groupId>
                    <artifactId>datanucleus-core</artifactId>
                    <version>1.1.5</version>
                    <exclusions>
                        <exclusion>
                            <groupId>javax.transaction</groupId>
                            <artifactId>transaction-api</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
                <dependency>
                    <groupId>org.datanucleus</groupId>
                    <artifactId>datanucleus-rdbms</artifactId>
                    <version>1.1.5</version>
                </dependency>
                <dependency>
                 <groupId>org.datanucleus</groupId>
                 <artifactId>datanucleus-enhancer</artifactId>
                <version>1.1.5</version>
           </dependency>
       </dependencies>
</plugin>

Now Google App Engine dependencies are added.

01
02
03
04
05
06
07
08
09
10
11
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-api-1.0-sdk</artifactId>
 <version>${gae.version}</version>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-tools-api</artifactId>
 <version>1.3.7</version>
</dependency>

Then if you want to test GAE functionalities (not used in our dummy project), next GAE libraries are added:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-api-labs</artifactId>
 <version>${gae.version}</version>
 <scope>test</scope>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-api-stubs</artifactId>
 <version>${gae.version}</version>
 <scope>test</scope>
</dependency>
 
<dependency>
 <groupId>com.google.appengine</groupId>
 <artifactId>appengine-testing</artifactId>
 <version>${gae.version}</version>
 <scope>test</scope>
</dependency>

Next change is a modification on maven-war-plugin including appengine-web.xml into generated package:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-war-plugin</artifactId>
 <configuration>
  <webResources>
   <resource>
    <directory>src/main/webapp</directory>
    <filtering>true</filtering>
    <includes>
     <include>**/appengine-web.xml</include>
    </includes>
   </resource>
  </webResources>
 </configuration>
</plugin>

And finally adding maven-gae-plugin and configuring it to upload application to appspot.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<plugin>
 <groupId>net.kindleit</groupId>
 <artifactId>maven-gae-plugin</artifactId>
 <version>${gaePluginVersion}</version>
 <configuration>
  <serverId>appengine.google.com</serverId>
 </configuration>
 <dependencies>
  <dependency>
   <groupId>net.kindleit</groupId>
   <artifactId>gae-runtime</artifactId>
   <version>${gae.version}</version>
   <type>pom</type>
  </dependency>
 </dependencies>
</plugin>

See that <serviceId> tag contains the server name defined previously in settings.xml file.

Also if you are using maven-release-plugin you can upload application to the appspot automatically, during release:perform goal:

1
2
3
4
5
6
7
8
<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-release-plugin</artifactId>
        <version>2.2.1</version>
        <configuration>
              <goals>gae:deploy</goals>
        </configuration>
</plugin>

Now run gae:deploy goal. If you have already installed Appengine Java SDK, then your application will be uploaded to your GAE site. But if it is the first time you run the plugin, you will receive an error. Do not panic, this error occurs because Maven plugin does not find Appengine SDK into directory you specified in <gae.home> tag. But if you have configured gae.home location into your local Maven repository, simply run gae:unpack goal, and SDK will be installed correctly so when you rerun gae:deploy your application will be uploaded into Google infrastructure.

In post example you can go to http://alexsotoblog.appspot.com/characters/1http://alexsotoblog.appspot.com/characters/1 and character information in JSON format is displayed into your browser.

As I have noted at the beginning of the post, the same process can be used for any web application, not only for Spring Rest MVC.

Because of teaching purpose all modifications have been made into application pom. My advice is that you create a parent pom with GAE related tags, so each project that must be uploaded into Google App Engine extends from same pom file.

I wish you have found this post useful.

This week I am at devoxx, meet me there ;) I will be speaking on Thursday 17 at 13:00 about Speeding Up Javascript & CSS Download Times With Aggregation and Minification.

Full pom file:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<?xml version="1.0" encoding="UTF-8"?>
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.springframework</groupId>
 <artifactId>rest</artifactId>
 <name>Rest</name>
 <packaging>war</packaging>
 <version>1.0.0-BUILD-SNAPSHOT</version>
 <properties>
  <java-version>1.6</java-version>
  <org.springframework-version>3.0.4.RELEASE</org.springframework-version>
  <org.aspectj-version>1.6.9</org.aspectj-version>
  <org.slf4j-version>1.5.10</org.slf4j-version>
  <!-- Specify AppEngine version for your project. It should match SDK version
   pointed to by ${gae.home} property (Typically, one used by your Eclipse plug-in) -->
 
  <gae.home>/home/alex/.m2/repository/com/google/appengine/appengine-java-sdk/1.5.5/appengine-java-sdk-1.5.5</gae.home>
  <gaeApplicationName>alexsotoblog</gaeApplicationName>
  <gaePluginVersion>0.9.0</gaePluginVersion>
  <gae.version>1.5.5</gae.version>
 
  <!-- Upload to http://test.latest.<applicationName>.appspot.com by default -->
  <gae.application.version>test</gae.application.version>
 </properties>
 <dependencies>
 
  <!-- Rest -->
  <dependency>
   <groupId>com.sun.xml.bind</groupId>
   <artifactId>jaxb-impl</artifactId>
   <version>2.2.4-1</version>
  </dependency>
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-core-lgpl</artifactId>
   <version>1.8.5</version>
  </dependency>
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-mapper-lgpl</artifactId>
   <version>1.8.5</version>
  </dependency>
 
  <!-- GAE libraries for local testing as described here: http://code.google.com/appengine/docs/java/howto/unittesting.html -->
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-api-labs</artifactId>
   <version>${gae.version}</version>
   <scope>test</scope>
  </dependency>
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-api-stubs</artifactId>
   <version>${gae.version}</version>
   <scope>test</scope>
  </dependency>
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-testing</artifactId>
   <version>${gae.version}</version>
   <scope>test</scope>
  </dependency>
 
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-api-1.0-sdk</artifactId>
   <version>${gae.version}</version>
  </dependency>
 
  <dependency>
   <groupId>com.google.appengine</groupId>
   <artifactId>appengine-tools-api</artifactId>
   <version>1.3.7</version>
  </dependency>
 
  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${org.springframework-version}</version>
   <exclusions>
    <!-- Exclude Commons Logging in favor of SLF4j -->
    <exclusion>
     <groupId>commons-logging</groupId>
     <artifactId>commons-logging</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-oxm</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
 
  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>${org.aspectj-version}</version>
  </dependency>
 
  <!-- Logging -->
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>${org.slf4j-version}</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>jcl-over-slf4j</artifactId>
   <version>${org.slf4j-version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>${org.slf4j-version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.15</version>
   <exclusions>
    <exclusion>
     <groupId>javax.mail</groupId>
     <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
     <groupId>javax.jms</groupId>
     <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jdmk</groupId>
     <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jmx</groupId>
     <artifactId>jmxri</artifactId>
    </exclusion>
   </exclusions>
   <scope>runtime</scope>
  </dependency>
 
  <!-- @Inject -->
  <dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
  </dependency>
 
  <!-- Servlet -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 
  <!-- Test -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
 
 </dependencies>
 <repositories>
  <!-- For testing against latest Spring snapshots -->
  <repository>
   <id>org.springframework.maven.snapshot</id>
   <name>Spring Maven Snapshot Repository</name>
   <releases>
    <enabled>false</enabled>
   </releases>
   <snapshots>
    <enabled>true</enabled>
   </snapshots>
  </repository>
  <!-- For developing against latest Spring milestones -->
  <repository>
   <id>org.springframework.maven.milestone</id>
   <name>Spring Maven Milestone Repository</name>
   <snapshots>
    <enabled>false</enabled>
   </snapshots>
  </repository>
  <!-- GAE repositories -->
  <repository>
   <id>maven-gae-plugin-repo</id>
   <name>maven-gae-plugin repository</name>
  </repository>
 </repositories>
 
 <pluginRepositories>
  <pluginRepository>
   <id>maven-gae-plugin-repo</id>
   <name>Maven Google App Engine Repository</name>
  </pluginRepository>
 </pluginRepositories>
 
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>${java-version}</source>
     <target>${java-version}</target>
    </configuration>
   </plugin>
 
   <!-- Adding appengine-web into war -->
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
     <webResources>
      <resource>
       <directory>src/main/webapp</directory>
       <filtering>true</filtering>
       <includes>
        <include>**/appengine-web.xml</include>
       </includes>
      </resource>
     </webResources>
     <warName>abc</warName>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>install</id>
      <phase>install</phase>
      <goals>
       <goal>sources</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <!-- Have to use version 1.2 since version 1.3 does not appear to work
     with ITDs -->
    <version>1.2</version>
    <dependencies>
     <!-- You must use Maven 2.0.9 or above or these are ignored (see MNG-2972) -->
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${org.aspectj-version}</version>
     </dependency>
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjtools</artifactId>
      <version>${org.aspectj-version}</version>
     </dependency>
    </dependencies>
    <executions>
     <execution>
      <goals>
       <goal>compile</goal>
       <goal>test-compile</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <outxml>true</outxml>
     <source>${java-version}</source>
     <target>${java-version}</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
     <junitArtifactName>junit:junit</junitArtifactName>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>tomcat-maven-plugin</artifactId>
    <version>1.0-beta-1</version>
   </plugin>
   <!-- The actual maven-gae-plugin. Type "mvn gae:run" to run project, "mvn
    gae:deploy" to upload to GAE. -->
   <plugin>
    <groupId>net.kindleit</groupId>
    <artifactId>maven-gae-plugin</artifactId>
    <version>${gaePluginVersion}</version>
    <configuration>
     <serverId>appengine.google.com</serverId>
    </configuration>
    <dependencies>
     <dependency>
      <groupId>net.kindleit</groupId>
      <artifactId>gae-runtime</artifactId>
      <version>${gae.version}</version>
      <type>pom</type>
     </dependency>
    </dependencies>
   </plugin>
  </plugins>
 </build>
</project>

Download Code.
Music: http://www.youtube.com/watch?v=Nba3Tr_GLZU

Reference: Spring MVC and REST at Google App Engine from our JCG partner Alex Soto at the One Jar To Rule Them All blog.

Related Articles :

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ganeshji Marwaha
Ganeshji Marwaha
13 years ago

Excellent article. Can you add how to test the GAE app in dev mode without uploading it to the server as well. 

rajan
rajan
11 years ago

run maven goal:
mvn jetty:run (it will run this application on jetty server on your localhost)

Once, server starts: go to browser > http://localhost:8080/characters/1

Thanks,
Rajan

oussama zoghlami
oussama zoghlami
13 years ago

Very useful, thank you :)))

Paulo Henrique Alves
12 years ago

Very usefull!!
I put true into my appengine-web.xml

Jayesh
Jayesh
12 years ago

Hi,

I am facing following issue can any one guide me what am I doing wrong. Struggling for almost a week. I have downloaded this example and trying to run but its not working. [ERROR] Unable to execute AppCfg

java.lang.ExceptionInInitializerError

at com.google.appengine.tools.util.Logging.initializeLogging(Logging.java:35)

at com.google.appengine.tools.admin.AppCfg.main(AppCfg.java:94)

at net.kindleit.gae.EngineGoalBase$1.run(EngineGoalBase.java:318)

Caused by: java.lang.IllegalArgumentException: Unable to find C:Erndinstallslibshared

at com.google.appengine.tools.info.SdkInfo._getLibs(SdkInfo.java:76)

at com.google.appengine.tools.info.SdkInfo.getLibsRecursive(SdkInfo.java:69)

at com.google.appengine.tools.info.SdkInfo.determineSharedLibFiles(SdkInfo.java:302)

at com.google.appengine.tools.info.SdkInfo.init(SdkInfo.java:237)

at com.google.appengine.tools.info.SdkInfo.getSdkRoot(SdkInfo.java:190)

at com.google.appengine.tools.info.SdkImplInfo.(SdkImplInfo.java:19)

… 3 more

Back to top button