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