提交 fb7c2a32 编写于 作者: J Jake Wharton

Support iterable and array-based OkHttp Part parts.

Also forbid OkHttp Part parts in iterables and arrays when a part name was specified.
上级 1b05fc97
......@@ -540,12 +540,33 @@ final class ServiceMethod<T> {
String partName = part.value();
Class<?> rawParameterType = Utils.getRawType(type);
if (partName.isEmpty()) {
if (!MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = rawParameterType.getComponentType();
if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
return ParameterHandler.RawPart.INSTANCE;
} else {
throw parameterError(p,
"@Part annotation must supply a name or use MultipartBody.Part parameter type.");
}
return ParameterHandler.RawPart.INSTANCE;
} else {
Headers headers =
Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
......@@ -560,11 +581,19 @@ final class ServiceMethod<T> {
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
}
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
+ "include a part name in the annotation.");
}
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).array();
......
......@@ -1446,6 +1446,44 @@ public final class RequestBuilderTest {
}
}
@Test public void multipartIterableRequiresName() {
class Example {
@Multipart //
@POST("/foo/bar/") //
Call<ResponseBody> method(@Part List<RequestBody> part) {
return null;
}
}
try {
buildRequest(Example.class, new Object[] { null });
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage(
"@Part annotation must supply a name or use MultipartBody.Part parameter type. (parameter #1)\n"
+ " for method Example.method");
}
}
@Test public void multipartArrayRequiresName() {
class Example {
@Multipart //
@POST("/foo/bar/") //
Call<ResponseBody> method(@Part RequestBody[] part) {
return null;
}
}
try {
buildRequest(Example.class, new Object[] { null });
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage(
"@Part annotation must supply a name or use MultipartBody.Part parameter type. (parameter #1)\n"
+ " for method Example.method");
}
}
@Test public void multipartOkHttpPartForbidsName() {
class Example {
@Multipart //
......@@ -1491,6 +1529,71 @@ public final class RequestBuilderTest {
.contains("\r\nkat\r\n--");
}
@Test public void multipartOkHttpIterablePart() throws IOException {
class Example {
@Multipart //
@POST("/foo/bar/") //
Call<ResponseBody> method(@Part List<MultipartBody.Part> part) {
return null;
}
}
MultipartBody.Part part1 = MultipartBody.Part.createFormData("foo", "bar");
MultipartBody.Part part2 = MultipartBody.Part.createFormData("kit", "kat");
Request request = buildRequest(Example.class, Arrays.asList(part1, part2));
assertThat(request.method()).isEqualTo("POST");
assertThat(request.headers().size()).isZero();
assertThat(request.url().toString()).isEqualTo("http://example.com/foo/bar/");
RequestBody body = request.body();
Buffer buffer = new Buffer();
body.writeTo(buffer);
String bodyString = buffer.readUtf8();
assertThat(bodyString)
.contains("Content-Disposition: form-data;")
.contains("name=\"foo\"\r\n")
.contains("\r\nbar\r\n--");
assertThat(bodyString)
.contains("Content-Disposition: form-data;")
.contains("name=\"kit\"\r\n")
.contains("\r\nkat\r\n--");
}
@Test public void multipartOkHttpArrayPart() throws IOException {
class Example {
@Multipart //
@POST("/foo/bar/") //
Call<ResponseBody> method(@Part MultipartBody.Part[] part) {
return null;
}
}
MultipartBody.Part part1 = MultipartBody.Part.createFormData("foo", "bar");
MultipartBody.Part part2 = MultipartBody.Part.createFormData("kit", "kat");
Request request =
buildRequest(Example.class, new Object[] { new MultipartBody.Part[] { part1, part2 } });
assertThat(request.method()).isEqualTo("POST");
assertThat(request.headers().size()).isZero();
assertThat(request.url().toString()).isEqualTo("http://example.com/foo/bar/");
RequestBody body = request.body();
Buffer buffer = new Buffer();
body.writeTo(buffer);
String bodyString = buffer.readUtf8();
assertThat(bodyString)
.contains("Content-Disposition: form-data;")
.contains("name=\"foo\"\r\n")
.contains("\r\nbar\r\n--");
assertThat(bodyString)
.contains("Content-Disposition: form-data;")
.contains("name=\"kit\"\r\n")
.contains("\r\nkat\r\n--");
}
@Test public void multipartOkHttpPartWithFilename() throws IOException {
class Example {
@Multipart //
......@@ -1548,6 +1651,44 @@ public final class RequestBuilderTest {
.contains("\r\npong2\r\n--");
}
@Test public void multipartIterableOkHttpPart() {
class Example {
@Multipart //
@POST("/foo/bar/") //
Call<ResponseBody> method(@Part("ping") List<MultipartBody.Part> part) {
return null;
}
}
try {
buildRequest(Example.class, new Object[] { null });
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage(
"@Part parameters using the MultipartBody.Part must not include a part name in the annotation. (parameter #1)\n"
+ " for method Example.method");
}
}
@Test public void multipartArrayOkHttpPart() {
class Example {
@Multipart //
@POST("/foo/bar/") //
Call<ResponseBody> method(@Part("ping") MultipartBody.Part[] part) {
return null;
}
}
try {
buildRequest(Example.class, new Object[] { null });
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage(
"@Part parameters using the MultipartBody.Part must not include a part name in the annotation. (parameter #1)\n"
+ " for method Example.method");
}
}
@Test public void multipartWithEncoding() throws IOException {
class Example {
@Multipart //
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册