Re-packaging a WAR file into a JAR file

If you are migrating to the Java 11 runtime and your app does not use App Engine bundled services, you must re-package your App Engine Java 8 web application into an executable JAR file.

Your application must have a Main class that starts a web server which responds to HTTP requests on the port specified by the PORT environment variable, typically 8081.

For example:

import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class Main {

  public static void main(String[] args) throws IOException {
    // Create an instance of HttpServer bound to port defined by the 
    // PORT environment variable when present, otherwise on 8080.
    int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
    HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);

    // Set root URI path.
    server.createContext("/", (var t) -> {
      byte[] response = "Hello World from Google App Engine Java 11.".getBytes();
      t.sendResponseHeaders(200, response.length);
      try (OutputStream os = t.getResponseBody()) {
        os.write(response);
      }
    });

    // Start the server.
    server.start();
  }
}

WAR migration example

The following instructions demonstrate how to repackage an App Engine Java 8 hello-world application as a JAR to run on the Java 11 runtime.

The migration uses the appengine-simple-jetty-main artifact. This provides a Main class with a simple Jetty web server that loads a WAR file and packages your app into an executable JAR file:

  1. Clone the Embedded Jetty Server artifact to your local machine:

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples
    

    Alternatively, you can download the sample as a zip file and extract it.

  2. Change to the directory that contains the sample code:

    cd java-docs-samples/appengine-java11/appengine-simple-jetty-main/
    
  3. Install the dependency locally:

    mvn install
    
  4. Add the following code to your project pom.xml file:

    • appengine-simple-jetty-main dependency:
      <dependency>
        <groupId>com.example.appengine.demo</groupId>
        <artifactId>simple-jetty-main</artifactId>
        <version>1</version>
        <scope>provided</scope>
      </dependency>
    • maven-dependency plugin:
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <id>copy</id>
            <phase>prepare-package</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>
                ${project.build.directory}/appengine-staging
              </outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
      App Engine deploys files located in the ${build.directory}/appengine-staging directory. By adding the maven-dependency plugin to your build, App Engine installs your specified dependencies to the correct folder.
  5. Create an entrypoint element in your app.yaml file to call the appengine-simple-jetty-main object and pass your WAR file as an argument. For example, see the helloworld-servlet sample app.yaml file:

    runtime: java11
    entrypoint: 'java -cp "*" com.example.appengine.demo.jettymain.Main helloworld.war'
  6. To run your application locally:

    1. Package your application:

      mvn clean package
      
    2. Start the server with your WAR file as an argument.

      For example, you can start the server in the helloworld-servlet sample by running the following command from your java-docs-samples/appengine-java11/appengine-simple-jetty-main/ folder:

      mvn exec:java -Dexec.args="../helloworld-java8/target/helloworld.war"
      
    3. In your web browser, enter the following address:

      http://localhost:8080

  7. To deploy your application:

    gcloud tooling

    gcloud app deploy

    Maven plugin

    mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID

    Replace PROJECT_ID with the ID of your Cloud project. If your pom.xml file already specifies your project ID, you don't need to include the -Dapp.deploy.projectId property in the command you run.