Skip to content

Commit

Permalink
Allow specifying the filename of multipart requests in Reactive REST …
Browse files Browse the repository at this point in the history
…Client

Resolves: #22658
  • Loading branch information
geoand committed Jan 13, 2022
1 parent 260ebd4 commit 7bb63c0
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,7 @@ private ResultHandle createMultipartForm(MethodCreator methodCreator, ResultHand

String formParamName = formParamName(field);
String partType = formPartType(field);
String partFilename = formPartFilename(field);

Type fieldType = field.type();

Expand All @@ -1152,7 +1153,7 @@ private ResultHandle createMultipartForm(MethodCreator methodCreator, ResultHand
// we support string, and send it as an attribute
ClassInfo fieldClass = index.getClassByName(fieldType.name());
if (DotNames.STRING.equals(fieldClass.name())) {
addString(ifValueNotNull, multipartForm, formParamName, fieldValue);
addString(ifValueNotNull, multipartForm, formParamName, partFilename, fieldValue);
} else if (is(FILE, fieldClass, index)) {
// file is sent as file :)
if (partType == null) {
Expand All @@ -1162,18 +1163,18 @@ private ResultHandle createMultipartForm(MethodCreator methodCreator, ResultHand
}
ResultHandle filePath = ifValueNotNull.invokeVirtualMethod(
MethodDescriptor.ofMethod(File.class, "toPath", Path.class), fieldValue);
addFile(ifValueNotNull, multipartForm, formParamName, partType, filePath);
addFile(ifValueNotNull, multipartForm, formParamName, partType, partFilename, filePath);
} else if (is(PATH, fieldClass, index)) {
// and so is path
if (partType == null) {
throw new IllegalArgumentException(
"No @PartType annotation found on multipart form field of type Path: " +
formClass.name() + "." + field.name());
}
addFile(ifValueNotNull, multipartForm, formParamName, partType, fieldValue);
addFile(ifValueNotNull, multipartForm, formParamName, partType, partFilename, fieldValue);
} else if (is(BUFFER, fieldClass, index)) {
// and buffer
addBuffer(ifValueNotNull, multipartForm, formParamName, partType, fieldValue, field);
addBuffer(ifValueNotNull, multipartForm, formParamName, partType, partFilename, fieldValue, field);
} else { // assume POJO:
addPojo(ifValueNotNull, multipartForm, formParamName, partType, fieldValue, field);
}
Expand All @@ -1189,12 +1190,12 @@ private ResultHandle createMultipartForm(MethodCreator methodCreator, ResultHand
ResultHandle buffer = ifValueNotNull.invokeStaticInterfaceMethod(
MethodDescriptor.ofMethod(Buffer.class, "buffer", Buffer.class, byte[].class),
fieldValue);
addBuffer(ifValueNotNull, multipartForm, formParamName, partType, buffer, field);
addBuffer(ifValueNotNull, multipartForm, formParamName, partType, partFilename, buffer, field);
break;
case PRIMITIVE:
// primitives are converted to text and sent as attribute
ResultHandle string = primitiveToString(ifValueNotNull, fieldValue, field);
addString(ifValueNotNull, multipartForm, formParamName, string);
addString(ifValueNotNull, multipartForm, formParamName, partFilename, string);
break;
case PARAMETERIZED_TYPE:
ParameterizedType parameterizedType = fieldType.asParameterizedType();
Expand Down Expand Up @@ -1232,9 +1233,10 @@ private void addPojo(BytecodeCreator methodCreator, AssignableResultHandle multi
* {@link QuarkusMultipartForm#textFileUpload(String, String, String, String)}
*/
private void addFile(BytecodeCreator methodCreator, AssignableResultHandle multipartForm, String formParamName,
String partType, ResultHandle filePath) {
String partType, String partFilename, ResultHandle filePath) {
ResultHandle fileNamePath = methodCreator.invokeInterfaceMethod(PATH_GET_FILENAME, filePath);
ResultHandle fileName = methodCreator.invokeVirtualMethod(OBJECT_TO_STRING, fileNamePath);
ResultHandle fileName = partFilename != null ? methodCreator.load(partFilename)
: methodCreator.invokeVirtualMethod(OBJECT_TO_STRING, fileNamePath);
ResultHandle pathString = methodCreator.invokeVirtualMethod(OBJECT_TO_STRING, filePath);
if (partType.equalsIgnoreCase(MediaType.APPLICATION_OCTET_STREAM)) {
methodCreator.assign(multipartForm,
Expand Down Expand Up @@ -1286,13 +1288,18 @@ private ResultHandle primitiveToString(BytecodeCreator methodCreator, ResultHand
}
}

private ResultHandle partFilenameHandle(BytecodeCreator methodCreator, String partFilename) {
return partFilename != null ? methodCreator.load(partFilename) : methodCreator.loadNull();
}

private void addString(BytecodeCreator methodCreator, AssignableResultHandle multipartForm, String formParamName,
ResultHandle fieldValue) {
String partFilename, ResultHandle fieldValue) {
methodCreator.assign(multipartForm,
methodCreator.invokeVirtualMethod(
MethodDescriptor.ofMethod(QuarkusMultipartForm.class, "attribute", QuarkusMultipartForm.class,
String.class, String.class),
multipartForm, methodCreator.load(formParamName), fieldValue));
String.class, String.class, String.class),
multipartForm, methodCreator.load(formParamName), fieldValue,
partFilenameHandle(methodCreator, partFilename)));
}

private void addMultiAsFile(BytecodeCreator methodCreator, AssignableResultHandle multipartForm, String formParamName,
Expand Down Expand Up @@ -1327,7 +1334,9 @@ private void addMultiAsFile(BytecodeCreator methodCreator, AssignableResultHandl
}

private void addBuffer(BytecodeCreator methodCreator, AssignableResultHandle multipartForm, String formParamName,
String partType, ResultHandle buffer, FieldInfo field) {
String partType, String partFilename, ResultHandle buffer, FieldInfo field) {
ResultHandle filenameHandle = partFilename != null ? methodCreator.load(partFilename)
: methodCreator.load(formParamName);
if (partType == null) {
throw new IllegalArgumentException(
"No @PartType annotation found on multipart form field " +
Expand All @@ -1336,22 +1345,20 @@ private void addBuffer(BytecodeCreator methodCreator, AssignableResultHandle mul
if (partType.equalsIgnoreCase(MediaType.APPLICATION_OCTET_STREAM)) {
methodCreator.assign(multipartForm,
// MultipartForm#binaryFileUpload(String name, String filename, io.vertx.mutiny.core.buffer.Buffer content, String mediaType);
// filename = name
methodCreator.invokeVirtualMethod(
MethodDescriptor.ofMethod(QuarkusMultipartForm.class, "binaryFileUpload",
QuarkusMultipartForm.class, String.class, String.class, Buffer.class,
String.class),
multipartForm, methodCreator.load(formParamName), methodCreator.load(formParamName),
multipartForm, methodCreator.load(formParamName), filenameHandle,
buffer, methodCreator.load(partType)));
} else {
methodCreator.assign(multipartForm,
// MultipartForm#textFileUpload(String name, String filename, io.vertx.mutiny.core.buffer.Buffer content, String mediaType)
// filename = name
methodCreator.invokeVirtualMethod(
MethodDescriptor.ofMethod(QuarkusMultipartForm.class, "textFileUpload",
QuarkusMultipartForm.class, String.class, String.class, Buffer.class,
String.class),
multipartForm, methodCreator.load(formParamName), methodCreator.load(formParamName),
multipartForm, methodCreator.load(formParamName), filenameHandle,
buffer, methodCreator.load(partType)));
}
}
Expand All @@ -1364,6 +1371,14 @@ private String formPartType(FieldInfo field) {
return null;
}

private String formPartFilename(FieldInfo field) {
AnnotationInstance partType = field.annotation(ResteasyReactiveDotNames.PART_FILE_NAME);
if (partType != null) {
return partType.value().asString();
}
return null;
}

private String formParamName(FieldInfo field) {
AnnotationInstance restFormParam = field.annotation(ResteasyReactiveDotNames.REST_FORM_PARAM);
AnnotationInstance formParam = field.annotation(ResteasyReactiveDotNames.FORM_PARAM);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.jboss.resteasy.reactive.MultipartForm;
import org.jboss.resteasy.reactive.PartFilename;
import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -44,6 +45,18 @@ void shouldPassOriginalFileName() throws IOException {
assertThat(client.postMultipart(form)).isEqualTo(file.getName());
}

@Test
void shouldUseFileNameFromAnnotation() throws IOException {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);

File file = File.createTempFile("MultipartTest", ".txt");
file.deleteOnExit();

ClientForm2 form = new ClientForm2();
form.file = file;
assertThat(client.postMultipartWithPartFilename(form)).isEqualTo(ClientForm2.FILE_NAME);
}

@Path("/multipart")
@ApplicationScoped
public static class Resource {
Expand All @@ -66,11 +79,23 @@ public interface Client {
@Consumes(MediaType.MULTIPART_FORM_DATA)
String postMultipart(@MultipartForm ClientForm clientForm);

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
String postMultipartWithPartFilename(@MultipartForm ClientForm2 clientForm);
}

public static class ClientForm {
@FormParam("myFile")
@PartType(MediaType.APPLICATION_OCTET_STREAM)
public File file;
}

public static class ClientForm2 {
public static final String FILE_NAME = "clientFile";

@FormParam("myFile")
@PartType(MediaType.APPLICATION_OCTET_STREAM)
@PartFilename(FILE_NAME)
public File file;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public Charset getCharset() {
return charset;
}

public QuarkusMultipartForm attribute(String name, String value) {
parts.add(new QuarkusMultipartFormDataPart(name, value));
public QuarkusMultipartForm attribute(String name, String value, String filename) {
parts.add(new QuarkusMultipartFormDataPart(name, value, filename));
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public QuarkusMultipartFormDataPart(String name, String filename, Multi<Byte> co
this.content = null;
}

public QuarkusMultipartFormDataPart(String name, String value) {
public QuarkusMultipartFormDataPart(String name, String value, String filename) {
if (name == null) {
throw new NullPointerException("Multipart field name cannot be null");
}
Expand All @@ -72,7 +72,7 @@ public QuarkusMultipartFormDataPart(String name, String value) {
}
this.name = name;
this.value = value;
this.filename = null;
this.filename = filename;
this.pathname = null;
this.content = null;
this.multiByteContent = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.jboss.jandex.DotName;
import org.jboss.resteasy.reactive.DummyElementType;
import org.jboss.resteasy.reactive.MultipartForm;
import org.jboss.resteasy.reactive.PartFilename;
import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.RestCookie;
import org.jboss.resteasy.reactive.RestForm;
Expand Down Expand Up @@ -126,6 +127,7 @@ public final class ResteasyReactiveDotNames {
public static final DotName REST_FORM_PARAM = DotName.createSimple(RestForm.class.getName());
public static final DotName MULTI_PART_FORM_PARAM = DotName.createSimple(MultipartForm.class.getName());
public static final DotName PART_TYPE_NAME = DotName.createSimple(PartType.class.getName());
public static final DotName PART_FILE_NAME = DotName.createSimple(PartFilename.class.getName());
public static final DotName REST_MATRIX_PARAM = DotName.createSimple(RestMatrix.class.getName());
public static final DotName REST_COOKIE_PARAM = DotName.createSimple(RestCookie.class.getName());
public static final DotName GET = DotName.createSimple(javax.ws.rs.GET.class.getName());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.jboss.resteasy.reactive;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Used on fields of {@link MultipartForm} POJOs to designate the filename of a part.
* This is only applicable in the client, not the server.
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PartFilename {
String value();
}

0 comments on commit 7bb63c0

Please sign in to comment.