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);
+ }
+}