Skip to content

Commit a65d5ac

Browse files
authored
feat: add appengine maven sample for jdk 21 (#9432)
1 parent 559d951 commit a65d5ac

File tree

6 files changed

+334
-0
lines changed

6 files changed

+334
-0
lines changed

appengine-java21/helloworld/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
HelloWorld for App Engine Standard (Java 21)
2+
============================
3+
4+
This sample demonstrates how to deploy an application on Google App Engine.
5+
6+
See the [Google App Engine standard environment documentation][ae-docs] for more
7+
detailed instructions.
8+
9+
[ae-docs]: https://cloud.google.com/appengine/docs/java/
10+
11+
12+
* [Java 21](https://www.oracle.com/java/technologies/downloads/)
13+
* [Maven](https://maven.apache.org/download.cgi) (at least 3.5)
14+
* [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud)
15+
16+
## Setup
17+
18+
• Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)
19+
20+
```
21+
gcloud init
22+
```
23+
24+
* Create an App Engine app within the current Google Cloud Project
25+
26+
```
27+
gcloud app create
28+
```
29+
30+
* In the `pom.xml`, update the [App Engine Maven Plugin](https://cloud.google.com/appengine/docs/standard/java/tools/maven-reference)
31+
with your Google Cloud Project Id:
32+
33+
```
34+
<plugin>
35+
<groupId>com.google.cloud.tools</groupId>
36+
<artifactId>appengine-maven-plugin</artifactId>
37+
<version>2.8.0</version>
38+
<configuration>
39+
<projectId>myProjectId</projectId>
40+
<version>GCLOUD_CONFIG</version>
41+
</configuration>
42+
</plugin>
43+
```
44+
**Note:** `GCLOUD_CONFIG` is a special version for autogenerating an App Engine
45+
version. Change this field to specify a specific version name.
46+
47+
## Maven
48+
### Running locally
49+
50+
mvn package appengine:run
51+
52+
To use vist: http://localhost:8080/
53+
54+
### Deploying
55+
56+
mvn package appengine:deploy
57+
58+
To use vist: https://YOUR-PROJECT-ID.appspot.com
59+
60+
## Testing
61+
62+
mvn verify
63+
64+
65+
As you add / modify the source code (`src/main/java/...`) it's very useful to add [unit testing](https://cloud.google.com/appengine/docs/java/tools/localunittesting)
66+
to (`src/main/test/...`). The following resources are quite useful:
67+
68+
* [Junit4](http://junit.org/junit4/)
69+
* [Mockito](http://mockito.org/)
70+
* [Truth](http://google.github.io/truth/)

appengine-java21/helloworld/pom.xml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2024 Google LLC
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18+
19+
<modelVersion>4.0.0</modelVersion>
20+
<!-- &lt;!&ndash; REQUIRED : your application must be packed as a .war to deploy on App Engine Standard &ndash;&gt;-->
21+
<packaging>war</packaging>
22+
<groupId>com.example.appengine</groupId>
23+
<artifactId>helloworld-jdk21</artifactId>
24+
<version>1.0-SNAPSHOT</version>
25+
26+
<parent>
27+
<groupId>com.google.cloud.samples</groupId>
28+
<artifactId>shared-configuration</artifactId>
29+
<version>1.2.2</version>
30+
</parent>
31+
32+
<properties>
33+
<maven.compiler.source>21</maven.compiler.source>
34+
<maven.compiler.target>21</maven.compiler.target>
35+
</properties>
36+
37+
<dependencies>
38+
<!-- Compile/runtime dependencies -->
39+
<!-- App Engine SDK dependency : only required if you need to explicitly use App Engine API -->
40+
<dependency>
41+
<groupId>com.google.appengine</groupId>
42+
<artifactId>appengine-api-1.0-sdk</artifactId>
43+
<version>2.0.23</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>jakarta.servlet</groupId>
47+
<artifactId>jakarta.servlet-api</artifactId>
48+
<version>6.1.0</version>
49+
<type>jar</type>
50+
<scope>provided</scope>
51+
</dependency>
52+
53+
<!-- Test Dependencies -->
54+
<dependency>
55+
<groupId>com.google.appengine</groupId>
56+
<artifactId>appengine-testing</artifactId>
57+
<version>2.0.23</version>
58+
<scope>test</scope>
59+
</dependency>
60+
<dependency>
61+
<groupId>com.google.appengine</groupId>
62+
<artifactId>appengine-api-stubs</artifactId>
63+
<version>2.0.23</version>
64+
<scope>test</scope>
65+
</dependency>
66+
<dependency>
67+
<groupId>com.google.appengine</groupId>
68+
<artifactId>appengine-tools-sdk</artifactId>
69+
<version>2.0.23</version>
70+
<scope>test</scope>
71+
</dependency>
72+
73+
<dependency>
74+
<groupId>com.google.truth</groupId>
75+
<artifactId>truth</artifactId>
76+
<version>1.1.5</version>
77+
<scope>test</scope>
78+
</dependency>
79+
<dependency>
80+
<groupId>junit</groupId>
81+
<artifactId>junit</artifactId>
82+
<version>4.13.2</version>
83+
<scope>test</scope>
84+
</dependency>
85+
<dependency>
86+
<groupId>org.mockito</groupId>
87+
<artifactId>mockito-core</artifactId>
88+
<version>4.11.0</version>
89+
<scope>test</scope>
90+
</dependency>
91+
</dependencies>
92+
93+
<build>
94+
<!-- &lt;!&ndash; for hot reload of the web application&ndash;&gt;-->
95+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
96+
<plugins>
97+
<plugin>
98+
<groupId>org.apache.maven.plugins</groupId>
99+
<artifactId>maven-war-plugin</artifactId>
100+
<version>3.4.0</version>
101+
</plugin>
102+
<plugin>
103+
<groupId>com.google.cloud.tools</groupId>
104+
<artifactId>appengine-maven-plugin</artifactId>
105+
<version>2.8.0</version>
106+
<configuration>
107+
<!-- can be set w/ -DprojectId=myProjectId on command line -->
108+
<projectId>myProjectId</projectId>
109+
<!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
110+
<version>GCLOUD_CONFIG</version>
111+
</configuration>
112+
</plugin>
113+
</plugins>
114+
</build>
115+
</project>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine.java21;
18+
19+
import com.google.appengine.api.utils.SystemProperty;
20+
import jakarta.servlet.annotation.WebServlet;
21+
import jakarta.servlet.http.HttpServlet;
22+
import jakarta.servlet.http.HttpServletRequest;
23+
import jakarta.servlet.http.HttpServletResponse;
24+
import java.io.IOException;
25+
import java.util.Properties;
26+
27+
// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
28+
@WebServlet(name = "HelloAppEngine", value = "/hello")
29+
public class HelloAppEngine extends HttpServlet {
30+
31+
@Override
32+
public void doGet(HttpServletRequest request, HttpServletResponse response)
33+
throws IOException {
34+
Properties properties = System.getProperties();
35+
36+
response.setContentType("text/plain");
37+
response.getWriter().println("Hello App Engine - Standard using "
38+
+ SystemProperty.version.get() + " Java "
39+
+ properties.get("java.specification.version"));
40+
}
41+
42+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
3+
<runtime>java21</runtime>
4+
<app-engine-apis>true</app-engine-apis>
5+
</appengine-web-app>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
4+
version="6.0">
5+
<runtime>java21</runtime> <!-- or another supported version -->
6+
<servlet>
7+
<servlet-name>helloworld</servlet-name>
8+
<servlet-class>com.example.appengine.java21.HelloAppEngine</servlet-class>
9+
</servlet>
10+
<servlet-mapping>
11+
<servlet-name>helloworld</servlet-name>
12+
<url-pattern>/*</url-pattern>
13+
</servlet-mapping>
14+
<app-engine-apis>true</app-engine-apis>
15+
</web-app>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine.java21;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.mockito.Mockito.when;
21+
22+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
23+
import jakarta.servlet.http.HttpServletRequest;
24+
import jakarta.servlet.http.HttpServletResponse;
25+
import java.io.PrintWriter;
26+
import java.io.StringWriter;
27+
import org.junit.After;
28+
import org.junit.Before;
29+
import org.junit.Test;
30+
import org.junit.runner.RunWith;
31+
import org.junit.runners.JUnit4;
32+
import org.mockito.Mock;
33+
import org.mockito.MockitoAnnotations;
34+
35+
/**
36+
* Unit tests for {@link HelloAppEngine}.
37+
*/
38+
@RunWith(JUnit4.class)
39+
public class HelloAppEngineTest {
40+
41+
private static final String FAKE_URL = "fake.fk/hello";
42+
// Set up a helper so that the ApiProxy returns a valid environment for local testing.
43+
private final LocalServiceTestHelper helper = new LocalServiceTestHelper();
44+
45+
@Mock
46+
private HttpServletRequest mockRequest;
47+
@Mock
48+
private HttpServletResponse mockResponse;
49+
private StringWriter responseWriter;
50+
private HelloAppEngine servletUnderTest;
51+
52+
@Before
53+
public void setUp() throws Exception {
54+
MockitoAnnotations.openMocks(this);
55+
helper.setUp();
56+
57+
// Set up some fake HTTP requests
58+
when(mockRequest.getRequestURI()).thenReturn(FAKE_URL);
59+
60+
// Set up a fake HTTP response.
61+
responseWriter = new StringWriter();
62+
when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));
63+
64+
servletUnderTest = new HelloAppEngine();
65+
}
66+
67+
@After
68+
public void tearDown() {
69+
helper.tearDown();
70+
}
71+
72+
@Test
73+
public void doGetWritesResponse() throws Exception {
74+
servletUnderTest.doGet(mockRequest, mockResponse);
75+
76+
// We expect our hello world response.
77+
assertThat(responseWriter.toString())
78+
.contains("Hello App Engine - Standard ");
79+
}
80+
81+
@Test
82+
public void helloInfoTest() {
83+
String result = HelloAppEngine.getInfo();
84+
assertThat(result)
85+
.containsMatch("^Version:\\s+.+OS:\\s+.+User:\\s");
86+
}
87+
}

0 commit comments

Comments
 (0)