Created an example with Jakarta REST 3.1 SeBootstrap & Multipart

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/examples/multipart-webapp/README.MD b/examples/multipart-webapp/README.MD
index 672fda0..ef421c2 100644
--- a/examples/multipart-webapp/README.MD
+++ b/examples/multipart-webapp/README.MD
@@ -1,4 +1,4 @@
-[//]: # " Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. "
+[//]: # " Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved. "
 [//]: # " "
 [//]: # " This program and the accompanying materials are made available under the "
 [//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
@@ -10,20 +10,23 @@
 =========================
 
 This example demonstrates how to develop RESTful web service with
-demonstrating JAX-RS Integration with MIME MultiPart Message Formats and
-an Jakarta EE 9 compliant Web container.
+demonstrating Jakarta-REST Integration with MIME MultiPart Message Formats and
+a Jakarta EE 9 compliant Web container.
+
+Please see also comparable example demonstrating usage of Jakarta REST 3.1 API for
+MIME MultiPart Message Formats (JERSEY_ROOT/examples/rest31-sebootstrap-multipart)
 
 Contents
 --------
 
 The mapping of the URI path space is presented in the following table:
 
-URI path                     | Description                                    | Sample request using curl
----------------------------- | ---------------------------------------------- | -----------------------------------------------------------------------------------------------
-**_/form/part_**             | POST message returning entire string           | `curl -X POST -F "part=part1"  http://localhost:8080/multipart-webapp/form/part`
-**_/form/part-file-name_**   | POST message returning part filename string.   | Be sure to execute this curl from project directory where pom.xml resides
-                             |                                                | `curl -X POST -F "part=@pom.xml"  http://localhost:8080/multipart-webapp/form/part-file-name`
-**_/form/xml-jaxb-part_**    | POST message returning xml jaxb part string.   | No curl sample available, please check test sources.
+ URI path                   | Description                                  | Sample request using curl
+----------------------------|----------------------------------------------| -----------------------------------------------------------------------------------------------
+ **_/form/part_**           | POST message returning entire string         | `curl -X POST -F "part=part1"  http://localhost:8080/multipart-webapp/form/part`
+ **_/form/part-file-name_** | POST message returning part filename string. | Be sure to execute this curl from project directory where pom.xml resides
+|                           |                                              | `curl -X POST -F "part=@pom.xml"  http://localhost:8080/multipart-webapp/form/part-file-name`
+ **_/form/xml-jaxb-part_**  | POST message returning xml jaxb part string. | No curl sample available, please check test sources.
 
 Running the Example
 -------------------
@@ -32,4 +35,4 @@
 
 > `mvn clean package jetty:run`
 
-Following steps are using [cURL](http://curl.haxx.se/) command line tool:
\ No newline at end of file
+The sample requests are using [cURL](http://curl.haxx.se/) command line tool.
\ No newline at end of file
diff --git a/examples/pom.xml b/examples/pom.xml
index 13d65e9..3863349 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -105,6 +105,7 @@
         <module>oauth-client-twitter</module>
         <!--<module>oauth2-client-google-webapp</module>-->
         <module>reload</module>
+        <module>rest31-sebootstrap-multipart</module>
         <module>rx-client-webapp</module>
         <module>server-async</module>
         <module>server-async-managed</module>
diff --git a/examples/rest31-sebootstrap-multipart/README.MD b/examples/rest31-sebootstrap-multipart/README.MD
new file mode 100644
index 0000000..804e7b6
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/README.MD
@@ -0,0 +1,37 @@
+[//]: # " Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. "
+[//]: # " "
+[//]: # " This program and the accompanying materials are made available under the "
+[//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
+[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. "
+[//]: # " "
+[//]: # " SPDX-License-Identifier: BSD-3-Clause "
+
+Multipart Web app Example
+=========================
+
+This example demonstrates how to develop RESTful web service with
+demonstrating Jakarta REST Integration with MIME MultiPart Message Formats and
+Jakarta REST EE 10 SeBootstrap functionality.
+
+Feel free to compare with pre-Jakarta REST 3.1 Jersey Multipart example (JERSEY_ROOT/examples/multipart-webapp).
+
+Contents
+--------
+
+The mapping of the URI path space is presented in the following table:
+
+ URI path                   | Description                                  | Sample request using curl
+----------------------------|----------------------------------------------| -----------------------------------------------------------------------------------------------
+ **_/form/part_**           | POST message returning entire string         | `curl -X POST -F "part=part1"  http://localhost:8080/multipart-webapp/form/part`
+ **_/form/part-file-name_** | POST message returning part filename string. | Be sure to execute this curl from project directory where pom.xml resides
+|                            |                                              | `curl -X POST -F "part=@pom.xml"  http://localhost:8080/multipart-webapp/form/part-file-name`
+ **_/form/xml-jaxb-part_**  | POST message returning xml jaxb part string. | No curl sample available, please check test sources.
+
+Running the Example
+-------------------
+
+You can run the example using Jetty as follows:
+
+> `mvn clean package exec:java`
+
+The sample requests are using [cURL](http://curl.haxx.se/) command line tool.
\ No newline at end of file
diff --git a/examples/rest31-sebootstrap-multipart/pom.xml b/examples/rest31-sebootstrap-multipart/pom.xml
new file mode 100644
index 0000000..9dd995a
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<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">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.glassfish.jersey.examples</groupId>
+        <artifactId>project</artifactId>
+        <version>3.1.99-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>rest31-sebootstrap-multipart</artifactId>
+    <name>jersey-examples-multipart-webapp</name>
+    <packaging>jar</packaging>
+
+    <description>Jersey SeBootstrap Multipart example.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-multipart</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-hk2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.xml.bind</groupId>
+            <artifactId>jakarta.xml.bind-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-osgi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-jdk-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-util</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>org.glassfish.jersey.examples.multipart.webapp.Main</mainClass>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>pre-release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Bean.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Bean.java
new file mode 100644
index 0000000..458222b
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Bean.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.multipart.webapp;
+
+import jakarta.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Bean {
+
+    public String value;
+
+    public Bean() {
+    }
+
+    public Bean(String str) {
+        value = str;
+    }
+
+}
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Main.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Main.java
new file mode 100644
index 0000000..5dbcfd0
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.multipart.webapp;
+
+import jakarta.ws.rs.SeBootstrap;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+public class Main {
+    public static void main(String[] args) throws ExecutionException, InterruptedException {
+        final SeBootstrap.Configuration.Builder bootstrapConfigurationBuilder = SeBootstrap.Configuration.builder();
+        bootstrapConfigurationBuilder.property(SeBootstrap.Configuration.PORT, 8080);
+
+        SeBootstrap.start(new MyApplication(), bootstrapConfigurationBuilder.build())
+            .whenComplete((instance1, throwable) -> {
+                try {
+                    System.out.println("Press enter to exit");
+                    System.in.read();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }).thenAccept((i) -> i.stop())
+
+            .toCompletableFuture().get();
+
+        System.out.println("Exiting...");
+    }
+}
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartResource.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartResource.java
new file mode 100644
index 0000000..dec7d0e
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartResource.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.multipart.webapp;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.EntityPart;
+import jakarta.ws.rs.core.MediaType;
+
+import java.io.IOException;
+
+@Path("/form")
+public class MultiPartResource {
+
+    @GET
+    @Path("test")
+    public String test() {
+        return "Test successful";
+    }
+
+    @POST
+    @Path("part")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    public String post(@FormParam("part") String s) {
+        return s;
+    }
+
+    @POST
+    @Path("part-file-name")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    public String post(@FormParam("part")EntityPart entityPart) throws IOException {
+        return entityPart.getContent(String.class) + ":" + entityPart.getFileName().get();
+    }
+
+    @POST
+    @Path("xml-jaxb-part")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    public String post(
+            @FormParam("string") EntityPart stringEntityPart,
+            @FormParam("bean") EntityPart beanEntityPart) throws IOException {
+        return stringEntityPart.getContent(String.class) + ":" + stringEntityPart.getFileName().get() + ","
+                + beanEntityPart.getContent(Bean.class).value + ":" + beanEntityPart.getFileName().get();
+    }
+}
diff --git a/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java
new file mode 100644
index 0000000..d9d7f30
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/src/main/java/org/glassfish/jersey/examples/multipart/webapp/MyApplication.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.multipart.webapp;
+
+import jakarta.ws.rs.ApplicationPath;
+
+import org.glassfish.jersey.server.ResourceConfig;
+
+@ApplicationPath("/multipart-webapp")
+public class MyApplication extends ResourceConfig {
+
+    public MyApplication() {
+        super(MultiPartResource.class);
+    }
+}
diff --git a/examples/rest31-sebootstrap-multipart/src/test/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartWebAppTest.java b/examples/rest31-sebootstrap-multipart/src/test/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartWebAppTest.java
new file mode 100644
index 0000000..218923f
--- /dev/null
+++ b/examples/rest31-sebootstrap-multipart/src/test/java/org/glassfish/jersey/examples/multipart/webapp/MultiPartWebAppTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.multipart.webapp;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.EntityPart;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.UriBuilder;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.internal.util.SaxHelper;
+import org.glassfish.jersey.internal.util.SimpleNamespaceResolver;
+import org.glassfish.jersey.test.JerseyTest;
+
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Document;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Tests for {@code MultipartResource} class.
+ *
+ * @author Naresh (Srinivas Bhimisetty)
+ * @author Michal Gajdos
+ */
+public class MultiPartWebAppTest extends JerseyTest {
+
+    public static final String PATH = MyApplication.class.getAnnotation(ApplicationPath.class).value();
+
+    @Override
+    protected URI getBaseUri() {
+        return UriBuilder.fromUri(super.getBaseUri()).path(PATH).build();
+    }
+
+    @Override
+    protected Application configure() {
+        return new MyApplication();
+    }
+
+    @Test
+    public void testApplicationWadl() throws Exception {
+        final WebTarget target = target().path(PATH + "/application.wadl");
+
+        final Response response = target.request().get();
+        assertEquals(200, response.getStatus());
+        final File tmpFile = response.readEntity(File.class);
+
+        final DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
+        bf.setNamespaceAware(true);
+        bf.setValidating(false);
+
+        if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
+            bf.setXIncludeAware(false);
+        }
+
+        final DocumentBuilder b = bf.newDocumentBuilder();
+        final Document d = b.parse(tmpFile);
+
+        final XPath xp = XPathFactory.newInstance().newXPath();
+        xp.setNamespaceContext(new SimpleNamespaceResolver("wadl", "http://wadl.dev.java.net/2009/02"));
+        String val = (String) xp.evaluate(
+                "//wadl:resource[@path='part']/wadl:method[@name='POST']/wadl:request/wadl:representation/@mediaType",
+                d, XPathConstants.STRING);
+
+        assertEquals("multipart/form-data", val);
+    }
+
+    @Test
+    public void testPart() throws IOException {
+        final WebTarget target = target().path(PATH + "/form/part");
+
+        final EntityPart entityPart = EntityPart.withName("part").content("CONTENT", String.class).build();
+        final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart)) {};
+
+        final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class);
+        assertEquals("CONTENT", s);
+    }
+
+    @Test
+    public void testPartWithFileName() throws IOException {
+        final WebTarget target = target().path(PATH + "/form/part-file-name");
+
+        final EntityPart entityPart = EntityPart.withName("part").fileName("file").content("CONTENT", String.class).build();
+        final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart)) {};
+
+        final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class);
+        assertEquals("CONTENT:file", s);
+    }
+
+    @Test
+    public void testXmlJAXBPart() throws IOException {
+        final WebTarget target = target().path(PATH + "/form/xml-jaxb-part");
+
+        final EntityPart entityPart1 = EntityPart.withName("bean").fileName("bean")
+                .content(new Bean("BEAN"), Bean.class)
+                .mediaType(MediaType.APPLICATION_XML_TYPE)
+                .build();
+        final EntityPart entityPart2 = EntityPart.withName("string").fileName("string")
+                .content("STRING", String.class)
+                .build();
+
+        final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(List.of(entityPart1, entityPart2)) {};
+
+        final String s = target.request().post(Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE), String.class);
+        assertEquals("STRING:string,BEAN:bean", s);
+    }
+}