Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pass correct filename on attachment upload #108

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.smartling.resteasy.ext;

import org.apache.commons.lang3.StringUtils;
import org.jboss.resteasy.annotations.providers.multipart.PartType;
import org.jboss.resteasy.plugins.providers.multipart.FieldEnablerPrivilegedAction;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormAnnotationWriter;
Expand Down Expand Up @@ -33,7 +34,8 @@ public class ExtendedMultipartFormWriter extends MultipartFormAnnotationWriter
@Override
protected void getFields(Class<?> type, MultipartFormDataOutput output, Object obj) throws IOException
{
for (Field field : type.getDeclaredFields())
Field[] declaredFields = type.getDeclaredFields();
for (Field field : declaredFields)
{
if (field.isAnnotationPresent(DynamicFormParam.class) && field.isAnnotationPresent(PartType.class))
{
Expand Down Expand Up @@ -84,11 +86,42 @@ protected void getFields(Class<?> type, MultipartFormDataOutput output, Object o
}
}
}
if (field.isAnnotationPresent(FileFormParam.class) && field.isAnnotationPresent(PartType.class))
{
AccessController.doPrivileged(new FieldEnablerPrivilegedAction(field));

FileFormParam fileFormParam = field.getAnnotation(FileFormParam.class);
String name = fileFormParam.value();
Object value = safeExtractValue(obj, field);
String mediaType = field.getAnnotation(PartType.class).value();
String filename = getFilename(obj, declaredFields, field);

output.addFormData(name, value, field.getType(), field.getGenericType(), MediaType.valueOf(mediaType), filename);
}
}

super.getFields(type, output, obj);
}

private String getFilename(Object obj, Field[] declaredFields, Field field)
{
String filenameField = field.getAnnotation(FileFormParam.class).filenameField();
if (StringUtils.isNotEmpty(filenameField))
{
for (Field declaredField : declaredFields)
{
if (declaredField.getName().equals(filenameField))
{
AccessController.doPrivileged(new FieldEnablerPrivilegedAction(declaredField));

return (String) safeExtractValue(obj, declaredField);
}
}
}

return getFilename(field);
}

private Object safeExtractValue(Object obj, Field field)
{
Object value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.smartling.resteasy.ext;

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

/**
* Must be used in conjunction with {@link org.jboss.resteasy.annotations.providers.multipart.PartType}.
* It defines file form data with filename.
* <p>
* It is a replacement for {@link javax.ws.rs.FormParam} and {@link org.jboss.resteasy.annotations.jaxrs.FormParam}
* and should not be used together on the same field.
* <p>
* Be careful, it may not fully replace FormParam functionality.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FileFormParam
{
String value();
String filenameField() default "";
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package com.smartling.resteasy.ext;

import com.smartling.resteasy.ext.data.FormWithDynamicParams;
import com.smartling.resteasy.ext.data.FormWithFileFormParams;
import com.smartling.resteasy.ext.data.FormWithListParams;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import org.junit.Before;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.lang.Boolean.TRUE;
import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
Expand Down Expand Up @@ -85,4 +88,26 @@ public void shouldExtractListFormParams() throws Exception
verifyNoMoreInteractions(output);
}

@Test
public void shouldExtractFileFormParams() throws Exception
{
MultipartFormDataOutput output = mock(MultipartFormDataOutput.class);
InputStream ins1 = mock(InputStream.class);
InputStream ins2 = mock(InputStream.class);
InputStream ins3 = mock(InputStream.class);

FormWithFileFormParams form = new FormWithFileFormParams();
form.setFile1(ins1);
form.setFile1Name("file1.txt");
form.setFile2(ins2);
form.setFile3(ins3);

testedInstance.getFields(FormWithFileFormParams.class, output, form);

verify(output).addFormData(eq("file1"), eq(ins1), eq(InputStream.class), eq(InputStream.class), eq(APPLICATION_OCTET_STREAM_TYPE), eq("file1.txt"));
verify(output).addFormData(eq("file2"), eq(ins2), eq(InputStream.class), eq(InputStream.class), eq(APPLICATION_OCTET_STREAM_TYPE), eq("file2"));
verify(output).addFormData(eq("file3"), eq(ins3), eq(InputStream.class), eq(InputStream.class), eq(APPLICATION_OCTET_STREAM_TYPE), isNull());
verify(output).addFormData(eq("file1Name"), eq("file1.txt"), eq(String.class), eq(String.class), eq(TEXT_PLAIN_TYPE), isNull());
verifyNoMoreInteractions(output);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ public interface DummyMultipartApi
@Consumes(MULTIPART_FORM_DATA)
@Path(DUMMY_MULTIPART_API + "/list-fields")
void postListParams(@MultipartForm FormWithListParams form);

@POST
@Consumes(MULTIPART_FORM_DATA)
@Path(DUMMY_MULTIPART_API + "/file-fields")
void postFileFormParams(@MultipartForm FormWithFileFormParams form);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.smartling.resteasy.ext.data;

import com.smartling.resteasy.ext.FileFormParam;
import lombok.Data;
import org.jboss.resteasy.annotations.providers.multipart.PartFilename;
import org.jboss.resteasy.annotations.providers.multipart.PartType;

import javax.ws.rs.FormParam;
import java.io.InputStream;

@Data
public class FormWithFileFormParams
{
@FileFormParam(value = "file1", filenameField = "file1Name")
@PartType("application/octet-stream")
private InputStream file1;

@FileFormParam("file2")
@PartFilename("file2")
@PartType("application/octet-stream")
private InputStream file2;

@FileFormParam("file3")
@PartType("application/octet-stream")
private InputStream file3;

@FormParam("file1Name")
@PartType("text/plain")
private String file1Name;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.smartling.resteasy.ext.ExtendedMultipartFormWriter;
import com.smartling.resteasy.ext.data.DummyMultipartApi;
import com.smartling.resteasy.ext.data.FormWithDynamicParams;
import com.smartling.resteasy.ext.data.FormWithFileFormParams;
import com.smartling.resteasy.ext.data.FormWithListParams;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.junit.Before;
Expand All @@ -12,6 +13,7 @@

import javax.ws.rs.client.ClientBuilder;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -99,4 +101,36 @@ public void shouldExtractListFormParams() throws Exception
.build())
);
}

@Test
public void shouldExtractFileFormParams() throws Exception
{
FormWithFileFormParams form = new FormWithFileFormParams();
form.setFile1(new ByteArrayInputStream("file1 data".getBytes(StandardCharsets.UTF_8)));
form.setFile1Name("file1.txt");
form.setFile2(new ByteArrayInputStream("file2 data".getBytes(StandardCharsets.UTF_8)));
form.setFile3(new ByteArrayInputStream("file3 data".getBytes(StandardCharsets.UTF_8)));


dummyApi().postFileFormParams(form);

dummyApiEndpoint.verify(postRequestedFor(urlEqualTo(DUMMY_MULTIPART_API + "/file-fields"))
.withRequestBodyPart(aMultipart()
.withHeader("Content-Disposition", equalTo("form-data; name=\"file1\"; filename=\"file1.txt\""))
.withBody(equalTo("file1 data"))
.build())
.withRequestBodyPart(aMultipart()
.withHeader("Content-Disposition", equalTo("form-data; name=\"file2\"; filename=\"file2\""))
.withBody(equalTo("file2 data"))
.build())
.withRequestBodyPart(aMultipart()
.withHeader("Content-Disposition", equalTo("form-data; name=\"file3\""))
.withBody(equalTo("file3 data"))
.build())
.withRequestBodyPart(aMultipart()
.withName("file1Name")
.withBody(equalTo("file1.txt"))
.build())
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.smartling.api.attachments.v2.pto;

import com.smartling.resteasy.ext.FileFormParam;
import com.smartling.resteasy.ext.ListFormParam;
import lombok.AllArgsConstructor;
import lombok.Data;
Expand All @@ -16,8 +17,7 @@
@AllArgsConstructor
public class AttachmentUploadPTO
{
@FormParam("file")
@PartFilename("file")
@FileFormParam(value = "file", filenameField = "name")
@PartType("application/octet-stream")
private InputStream file;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public void testUploadAttachment() throws Exception
String partSeparator = requestBody.substring(0, 38);

assertEquals(requestBody, partSeparator + "\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"file\"\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" +
"Content-Type: application/octet-stream\r\n" +
"\r\n" +
"content\r\n" +
Expand Down
Loading