Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wd1105040417
retrofit
提交
05560b7a
R
retrofit
项目概览
wd1105040417
/
retrofit
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
retrofit
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
05560b7a
编写于
2月 28, 2019
作者:
J
Jake Wharton
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add annotation for skipping the callback executor
上级
c2b930c9
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
199 addition
and
140 deletion
+199
-140
retrofit/src/main/java/retrofit2/DefaultCallAdapterFactory.java
...it/src/main/java/retrofit2/DefaultCallAdapterFactory.java
+85
-8
retrofit/src/main/java/retrofit2/ExecutorCallAdapterFactory.java
...t/src/main/java/retrofit2/ExecutorCallAdapterFactory.java
+0
-112
retrofit/src/main/java/retrofit2/Platform.java
retrofit/src/main/java/retrofit2/Platform.java
+3
-10
retrofit/src/main/java/retrofit2/SkipCallbackExecutor.java
retrofit/src/main/java/retrofit2/SkipCallbackExecutor.java
+50
-0
retrofit/src/main/java/retrofit2/Utils.java
retrofit/src/main/java/retrofit2/Utils.java
+0
-8
retrofit/src/test/java/retrofit2/DefaultCallAdapterFactoryTest.java
...rc/test/java/retrofit2/DefaultCallAdapterFactoryTest.java
+2
-2
retrofit/src/test/java/retrofit2/RetrofitTest.java
retrofit/src/test/java/retrofit2/RetrofitTest.java
+59
-0
未找到文件。
retrofit/src/main/java/retrofit2/DefaultCallAdapterFactory.java
浏览文件 @
05560b7a
...
...
@@ -15,33 +15,110 @@
*/
package
retrofit2
;
import
java.io.IOException
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.ParameterizedType
;
import
java.lang.reflect.Type
;
import
java.util.concurrent.Executor
;
import
javax.annotation.Nullable
;
import
okhttp3.Request
;
import
static
retrofit2
.
Utils
.
checkNotNull
;
/**
* Creates call adapters for that uses the same thread for both I/O and application-level
* callbacks. For synchronous calls this is the application thread making the request; for
* asynchronous calls this is a thread provided by OkHttp's dispatcher.
*/
final
class
DefaultCallAdapterFactory
extends
CallAdapter
.
Factory
{
static
final
CallAdapter
.
Factory
INSTANCE
=
new
DefaultCallAdapterFactory
();
private
final
@Nullable
Executor
callbackExecutor
;
DefaultCallAdapterFactory
(
@Nullable
Executor
callbackExecutor
)
{
this
.
callbackExecutor
=
callbackExecutor
;
}
@Override
public
@Nullable
CallAdapter
<?,
?>
get
(
Type
returnType
,
Annotation
[]
annotations
,
Retrofit
retrofit
)
{
if
(
getRawType
(
returnType
)
!=
Call
.
class
)
{
return
null
;
}
if
(!(
returnType
instanceof
ParameterizedType
))
{
throw
new
IllegalArgumentException
(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>"
);
}
final
Type
responseType
=
Utils
.
getParameterUpperBound
(
0
,
(
ParameterizedType
)
returnType
);
final
Executor
executor
=
Utils
.
isAnnotationPresent
(
annotations
,
SkipCallbackExecutor
.
class
)
?
null
:
callbackExecutor
;
final
Type
responseType
=
Utils
.
getCallResponseType
(
returnType
);
return
new
CallAdapter
<
Object
,
Call
<?>>()
{
@Override
public
Type
responseType
()
{
return
responseType
;
}
@Override
public
Call
<
Object
>
adapt
(
Call
<
Object
>
call
)
{
return
call
;
return
executor
==
null
?
call
:
new
ExecutorCallbackCall
<>(
executor
,
call
);
}
};
}
static
final
class
ExecutorCallbackCall
<
T
>
implements
Call
<
T
>
{
final
Executor
callbackExecutor
;
final
Call
<
T
>
delegate
;
ExecutorCallbackCall
(
Executor
callbackExecutor
,
Call
<
T
>
delegate
)
{
this
.
callbackExecutor
=
callbackExecutor
;
this
.
delegate
=
delegate
;
}
@Override
public
void
enqueue
(
final
Callback
<
T
>
callback
)
{
checkNotNull
(
callback
,
"callback == null"
);
delegate
.
enqueue
(
new
Callback
<
T
>()
{
@Override
public
void
onResponse
(
Call
<
T
>
call
,
final
Response
<
T
>
response
)
{
callbackExecutor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(
delegate
.
isCanceled
())
{
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback
.
onFailure
(
ExecutorCallbackCall
.
this
,
new
IOException
(
"Canceled"
));
}
else
{
callback
.
onResponse
(
ExecutorCallbackCall
.
this
,
response
);
}
}
});
}
@Override
public
void
onFailure
(
Call
<
T
>
call
,
final
Throwable
t
)
{
callbackExecutor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
callback
.
onFailure
(
ExecutorCallbackCall
.
this
,
t
);
}
});
}
});
}
@Override
public
boolean
isExecuted
()
{
return
delegate
.
isExecuted
();
}
@Override
public
Response
<
T
>
execute
()
throws
IOException
{
return
delegate
.
execute
();
}
@Override
public
void
cancel
()
{
delegate
.
cancel
();
}
@Override
public
boolean
isCanceled
()
{
return
delegate
.
isCanceled
();
}
@SuppressWarnings
(
"CloneDoesntCallSuperClone"
)
// Performing deep clone.
@Override
public
Call
<
T
>
clone
()
{
return
new
ExecutorCallbackCall
<>(
callbackExecutor
,
delegate
.
clone
());
}
@Override
public
Request
request
()
{
return
delegate
.
request
();
}
}
}
retrofit/src/main/java/retrofit2/ExecutorCallAdapterFactory.java
已删除
100644 → 0
浏览文件 @
c2b930c9
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
retrofit2
;
import
java.io.IOException
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.Type
;
import
java.util.concurrent.Executor
;
import
javax.annotation.Nullable
;
import
okhttp3.Request
;
import
static
retrofit2
.
Utils
.
checkNotNull
;
final
class
ExecutorCallAdapterFactory
extends
CallAdapter
.
Factory
{
final
Executor
callbackExecutor
;
ExecutorCallAdapterFactory
(
Executor
callbackExecutor
)
{
this
.
callbackExecutor
=
callbackExecutor
;
}
@Override
public
@Nullable
CallAdapter
<?,
?>
get
(
Type
returnType
,
Annotation
[]
annotations
,
Retrofit
retrofit
)
{
if
(
getRawType
(
returnType
)
!=
Call
.
class
)
{
return
null
;
}
final
Type
responseType
=
Utils
.
getCallResponseType
(
returnType
);
return
new
CallAdapter
<
Object
,
Call
<?>>()
{
@Override
public
Type
responseType
()
{
return
responseType
;
}
@Override
public
Call
<
Object
>
adapt
(
Call
<
Object
>
call
)
{
return
new
ExecutorCallbackCall
<>(
callbackExecutor
,
call
);
}
};
}
static
final
class
ExecutorCallbackCall
<
T
>
implements
Call
<
T
>
{
final
Executor
callbackExecutor
;
final
Call
<
T
>
delegate
;
ExecutorCallbackCall
(
Executor
callbackExecutor
,
Call
<
T
>
delegate
)
{
this
.
callbackExecutor
=
callbackExecutor
;
this
.
delegate
=
delegate
;
}
@Override
public
void
enqueue
(
final
Callback
<
T
>
callback
)
{
checkNotNull
(
callback
,
"callback == null"
);
delegate
.
enqueue
(
new
Callback
<
T
>()
{
@Override
public
void
onResponse
(
Call
<
T
>
call
,
final
Response
<
T
>
response
)
{
callbackExecutor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(
delegate
.
isCanceled
())
{
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback
.
onFailure
(
ExecutorCallbackCall
.
this
,
new
IOException
(
"Canceled"
));
}
else
{
callback
.
onResponse
(
ExecutorCallbackCall
.
this
,
response
);
}
}
});
}
@Override
public
void
onFailure
(
Call
<
T
>
call
,
final
Throwable
t
)
{
callbackExecutor
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
callback
.
onFailure
(
ExecutorCallbackCall
.
this
,
t
);
}
});
}
});
}
@Override
public
boolean
isExecuted
()
{
return
delegate
.
isExecuted
();
}
@Override
public
Response
<
T
>
execute
()
throws
IOException
{
return
delegate
.
execute
();
}
@Override
public
void
cancel
()
{
delegate
.
cancel
();
}
@Override
public
boolean
isCanceled
()
{
return
delegate
.
isCanceled
();
}
@SuppressWarnings
(
"CloneDoesntCallSuperClone"
)
// Performing deep clone.
@Override
public
Call
<
T
>
clone
()
{
return
new
ExecutorCallbackCall
<>(
callbackExecutor
,
delegate
.
clone
());
}
@Override
public
Request
request
()
{
return
delegate
.
request
();
}
}
}
retrofit/src/main/java/retrofit2/Platform.java
浏览文件 @
05560b7a
...
...
@@ -62,10 +62,7 @@ class Platform {
List
<?
extends
CallAdapter
.
Factory
>
defaultCallAdapterFactories
(
@Nullable
Executor
callbackExecutor
)
{
if
(
callbackExecutor
!=
null
)
{
return
singletonList
(
new
ExecutorCallAdapterFactory
(
callbackExecutor
));
}
return
singletonList
(
DefaultCallAdapterFactory
.
INSTANCE
);
return
singletonList
(
new
DefaultCallAdapterFactory
(
callbackExecutor
));
}
int
defaultCallAdapterFactoriesSize
()
{
...
...
@@ -111,11 +108,7 @@ class Platform {
@Nullable
Executor
callbackExecutor
)
{
List
<
CallAdapter
.
Factory
>
factories
=
new
ArrayList
<>(
2
);
factories
.
add
(
CompletableFutureCallAdapterFactory
.
INSTANCE
);
if
(
callbackExecutor
!=
null
)
{
factories
.
add
(
new
ExecutorCallAdapterFactory
(
callbackExecutor
));
}
else
{
factories
.
add
(
DefaultCallAdapterFactory
.
INSTANCE
);
}
factories
.
add
(
new
DefaultCallAdapterFactory
(
callbackExecutor
));
return
unmodifiableList
(
factories
);
}
...
...
@@ -148,7 +141,7 @@ class Platform {
@Override
List
<?
extends
CallAdapter
.
Factory
>
defaultCallAdapterFactories
(
@Nullable
Executor
callbackExecutor
)
{
if
(
callbackExecutor
==
null
)
throw
new
AssertionError
();
ExecutorCallAdapterFactory
executorFactory
=
new
Executor
CallAdapterFactory
(
callbackExecutor
);
DefaultCallAdapterFactory
executorFactory
=
new
Default
CallAdapterFactory
(
callbackExecutor
);
return
Build
.
VERSION
.
SDK_INT
>=
24
?
asList
(
CompletableFutureCallAdapterFactory
.
INSTANCE
,
executorFactory
)
:
singletonList
(
executorFactory
);
...
...
retrofit/src/main/java/retrofit2/SkipCallbackExecutor.java
0 → 100644
浏览文件 @
05560b7a
/*
* Copyright (C) 2019 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
retrofit2
;
import
java.lang.annotation.Annotation
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Target
;
import
java.lang.reflect.Type
;
import
static
java
.
lang
.
annotation
.
ElementType
.
METHOD
;
import
static
java
.
lang
.
annotation
.
RetentionPolicy
.
RUNTIME
;
/**
* Change the behavior of a {@code Call<BodyType>} return type to not use the
* {@linkplain Retrofit#callbackExecutor() callback executor} for invoking the
* {@link Callback#onResponse(Call, Response) onResponse} or
* {@link Callback#onFailure(Call, Throwable) onFailure} methods.
*
* <pre>{@code
* @SkipCallbackExecutor
* @Get("user/{id}/token")
* Call<String> getToken(@Path("id") long id);
* }</pre>
*
* This annotation can also be used when a {@link CallAdapter.Factory} <em>explicitly</em> delegates
* to the built-in factory for {@link Call} via
* {@link Retrofit#nextCallAdapter(CallAdapter.Factory, Type, Annotation[])} in order for the
* returned {@link Call} to skip the executor. (Note: by default, a {@link Call} supplied directly
* to a {@link CallAdapter} will already skip the callback executor. The annotation is only useful
* when looking up the built-in adapter.)
*/
@Documented
@Target
(
METHOD
)
@Retention
(
RUNTIME
)
public
@interface
SkipCallbackExecutor
{
}
retrofit/src/main/java/retrofit2/Utils.java
浏览文件 @
05560b7a
...
...
@@ -383,14 +383,6 @@ final class Utils {
+
"GenericArrayType, but <"
+
type
+
"> is of type "
+
className
);
}
static
Type
getCallResponseType
(
Type
returnType
)
{
if
(!(
returnType
instanceof
ParameterizedType
))
{
throw
new
IllegalArgumentException
(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>"
);
}
return
getParameterUpperBound
(
0
,
(
ParameterizedType
)
returnType
);
}
private
static
final
class
ParameterizedTypeImpl
implements
ParameterizedType
{
private
final
Type
ownerType
;
private
final
Type
rawType
;
...
...
retrofit/src/test/java/retrofit2/
Executor
CallAdapterFactoryTest.java
→
retrofit/src/test/java/retrofit2/
Default
CallAdapterFactoryTest.java
浏览文件 @
05560b7a
...
...
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.verify;
import
static
org
.
mockito
.
Mockito
.
verifyNoMoreInteractions
;
@SuppressWarnings
(
"unchecked"
)
public
final
class
Executor
CallAdapterFactoryTest
{
public
final
class
Default
CallAdapterFactoryTest
{
private
static
final
Annotation
[]
NO_ANNOTATIONS
=
new
Annotation
[
0
];
private
final
Retrofit
retrofit
=
new
Retrofit
.
Builder
()
...
...
@@ -45,7 +45,7 @@ public final class ExecutorCallAdapterFactoryTest {
runnable
.
run
();
}
});
private
final
CallAdapter
.
Factory
factory
=
new
Executor
CallAdapterFactory
(
callbackExecutor
);
private
final
CallAdapter
.
Factory
factory
=
new
Default
CallAdapterFactory
(
callbackExecutor
);
@Test
public
void
rawTypeThrows
()
{
try
{
...
...
retrofit/src/test/java/retrofit2/RetrofitTest.java
浏览文件 @
05560b7a
...
...
@@ -77,6 +77,9 @@ public final class RetrofitTest {
@GET
(
"/"
)
Call
<
okhttp3
.
Response
>
badType2
();
@GET
(
"/"
)
Call
<
ResponseBody
>
getResponseBody
();
@SkipCallbackExecutor
@GET
(
"/"
)
Call
<
ResponseBody
>
getResponseBodySkippedExecutor
();
@GET
(
"/"
)
Call
<
Void
>
getVoid
();
@POST
(
"/"
)
Call
<
ResponseBody
>
postRequestBody
(
@Body
RequestBody
body
);
@GET
(
"/"
)
Call
<
ResponseBody
>
queryString
(
@Query
(
"foo"
)
String
foo
);
...
...
@@ -1341,6 +1344,62 @@ public final class RetrofitTest {
verifyNoMoreInteractions
(
executor
);
}
@Test
public
void
skippedCallbackExecutorNotUsedForSuccess
()
throws
InterruptedException
{
Executor
executor
=
new
Executor
()
{
@Override
public
void
execute
(
Runnable
command
)
{
fail
();
}
};
Retrofit
retrofit
=
new
Retrofit
.
Builder
()
.
baseUrl
(
server
.
url
(
"/"
))
.
callbackExecutor
(
executor
)
.
build
();
CallMethod
service
=
retrofit
.
create
(
CallMethod
.
class
);
Call
<
ResponseBody
>
call
=
service
.
getResponseBodySkippedExecutor
();
server
.
enqueue
(
new
MockResponse
());
final
CountDownLatch
latch
=
new
CountDownLatch
(
1
);
call
.
enqueue
(
new
Callback
<
ResponseBody
>()
{
@Override
public
void
onResponse
(
Call
<
ResponseBody
>
call
,
Response
<
ResponseBody
>
response
)
{
latch
.
countDown
();
}
@Override
public
void
onFailure
(
Call
<
ResponseBody
>
call
,
Throwable
t
)
{
t
.
printStackTrace
();
}
});
assertTrue
(
latch
.
await
(
2
,
TimeUnit
.
SECONDS
));
}
@Test
public
void
skippedCallbackExecutorNotUsedForFailure
()
throws
InterruptedException
{
Executor
executor
=
new
Executor
()
{
@Override
public
void
execute
(
Runnable
command
)
{
fail
();
}
};
Retrofit
retrofit
=
new
Retrofit
.
Builder
()
.
baseUrl
(
server
.
url
(
"/"
))
.
callbackExecutor
(
executor
)
.
build
();
CallMethod
service
=
retrofit
.
create
(
CallMethod
.
class
);
Call
<
ResponseBody
>
call
=
service
.
getResponseBodySkippedExecutor
();
server
.
enqueue
(
new
MockResponse
().
setSocketPolicy
(
DISCONNECT_AT_START
));
final
CountDownLatch
latch
=
new
CountDownLatch
(
1
);
call
.
enqueue
(
new
Callback
<
ResponseBody
>()
{
@Override
public
void
onResponse
(
Call
<
ResponseBody
>
call
,
Response
<
ResponseBody
>
response
)
{
throw
new
AssertionError
();
}
@Override
public
void
onFailure
(
Call
<
ResponseBody
>
call
,
Throwable
t
)
{
latch
.
countDown
();
}
});
assertTrue
(
latch
.
await
(
2
,
TimeUnit
.
SECONDS
));
}
/** Confirm that Retrofit encodes parameters when the call is executed, and not earlier. */
@Test
public
void
argumentCapture
()
throws
Exception
{
AtomicInteger
i
=
new
AtomicInteger
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录