Support a single EntityPart as an entity
Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java
index 03bf661..c49be99 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/MultiPartFeature.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -26,6 +26,8 @@
import org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide;
import org.glassfish.jersey.media.multipart.internal.MultiPartReaderServerSide;
import org.glassfish.jersey.media.multipart.internal.MultiPartWriter;
+import org.glassfish.jersey.media.multipart.internal.SingleEntityPartReader;
+import org.glassfish.jersey.media.multipart.internal.SingleEntityPartWriter;
/**
* Feature used to register Multipart providers.
@@ -49,6 +51,8 @@
context.register(EntityPartReader.class);
context.register(EntityPartWriter.class);
+ context.register(SingleEntityPartReader.class);
+ context.register(SingleEntityPartWriter.class);
return true;
}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartReader.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartReader.java
new file mode 100644
index 0000000..9b7589e
--- /dev/null
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartReader.java
@@ -0,0 +1,83 @@
+/*
+ * 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 Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.media.multipart.internal;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.EntityPart;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.ext.MessageBodyReader;
+import jakarta.ws.rs.ext.Providers;
+import org.glassfish.jersey.media.multipart.BodyPart;
+import org.glassfish.jersey.media.multipart.FormDataBodyPart;
+import org.glassfish.jersey.media.multipart.JerseyEntityPartBuilderProvider;
+import org.glassfish.jersey.media.multipart.MultiPart;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.LinkedList;
+import java.util.List;
+
+public class SingleEntityPartReader implements MessageBodyReader<EntityPart> {
+
+ private MultiPartReaderClientSide multiPartReaderClientSide;
+
+ private final Providers providers;
+
+ @Inject
+ public SingleEntityPartReader(@Context Providers providers) {
+ this.providers = providers;
+ }
+
+ @Override
+ public boolean isReadable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) {
+ return EntityPart.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public EntityPart readFrom(Class<EntityPart> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
+ InputStream entityStream) throws IOException, WebApplicationException {
+
+ if (multiPartReaderClientSide == null) {
+ multiPartReaderClientSide = (MultiPartReaderClientSide) providers.getMessageBodyReader(
+ MultiPart.class, MultiPart.class, new Annotation[0], MediaType.MULTIPART_FORM_DATA_TYPE);
+ }
+
+ final MultiPart multiPart = multiPartReaderClientSide.readFrom(
+ MultiPart.class, MultiPart.class, annotations, mediaType, httpHeaders, entityStream);
+ final List<BodyPart> bodyParts = multiPart.getBodyParts();
+ final List<EntityPart> entityParts = new LinkedList<>();
+
+ for (BodyPart bp : bodyParts) {
+ if (FormDataBodyPart.class.isInstance(bp)) {
+ entityParts.add((EntityPart) bp);
+ } else {
+ final EntityPart ep = new JerseyEntityPartBuilderProvider().withName("")
+ .mediaType(bp.getMediaType()).content(bp.getEntity()).headers(bp.getHeaders()).build();
+ entityParts.add(ep);
+ }
+ // consume all bodyParts
+ }
+
+ return entityParts.get(0);
+ }
+}
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartWriter.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartWriter.java
new file mode 100644
index 0000000..9150dc6
--- /dev/null
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/SingleEntityPartWriter.java
@@ -0,0 +1,67 @@
+/*
+ * 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 Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.media.multipart.internal;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.EntityPart;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.ext.MessageBodyWriter;
+import jakarta.ws.rs.ext.Providers;
+import org.glassfish.jersey.media.multipart.BodyPart;
+import org.glassfish.jersey.media.multipart.MultiPart;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+public class SingleEntityPartWriter implements MessageBodyWriter<EntityPart> {
+
+ private MultiPartWriter multiPartWriter;
+
+ private final Providers providers;
+
+ @Inject
+ public SingleEntityPartWriter(@Context Providers providers) {
+ this.providers = providers;
+ }
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type generic, Annotation[] annotations, MediaType mediaType) {
+ return EntityPart.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public void writeTo(EntityPart entityParts, Class<?> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+ throws IOException, WebApplicationException {
+ final MultiPart multiPart = new MultiPart();
+ multiPart.setMediaType(mediaType);
+ multiPart.bodyPart((BodyPart) entityParts);
+
+ if (multiPartWriter == null) {
+ multiPartWriter = (MultiPartWriter) providers.getMessageBodyWriter(
+ MultiPart.class, MultiPart.class, new Annotation[0], MediaType.MULTIPART_FORM_DATA_TYPE);
+ }
+
+ multiPartWriter.writeTo(multiPart, MultiPart.class, MultiPart.class,
+ annotations, multiPart.getMediaType(), httpHeaders, entityStream);
+ }
+}
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java
index 084238f..e6bd4e6 100644
--- a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java
+++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/EntityPartTest.java
@@ -298,6 +298,21 @@
}
}
+ @Test
+ public void postHeaderNoListTest() throws IOException {
+ EntityPart entityPart = EntityPart.withName("name1").content("data1").header("header-01", "value-01").build();
+ Entity entity = Entity.entity(entityPart, MediaType.MULTIPART_FORM_DATA_TYPE);
+ try (Response response = target("/postHeaders").request().post(entity)) {
+ response.bufferEntity();
+ List<EntityPart> result = response.readEntity(LIST_ENTITY_PART_TYPE);
+ assertEquals("value-01", result.get(0).getHeaders().getFirst("header-01"));
+ assertEquals("data1", result.get(0).getContent(String.class));
+
+ EntityPart firstEntity = response.readEntity(EntityPart.class);
+ assertEquals("value-01", result.get(0).getHeaders().getFirst("header-01"));
+ }
+ }
+
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public static class AtomicReferenceProvider implements