Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
thythm
ribbon
提交
895eeff5
R
ribbon
项目概览
thythm
/
ribbon
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
ribbon
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
895eeff5
编写于
6月 20, 2014
作者:
T
Tomasz Bak
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Dynamic proxy client prototype.
上级
4cfb6bc6
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
758 addition
and
1 deletion
+758
-1
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/Ribbon.java
.../main/java/com/netflix/ribbonclientextensions/Ribbon.java
+2
-1
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplate.java
...ix/ribbonclientextensions/typedclient/MethodTemplate.java
+172
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplateExecutor.java
...nclientextensions/typedclient/MethodTemplateExecutor.java
+56
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/ReflectUtil.java
...tflix/ribbonclientextensions/typedclient/ReflectUtil.java
+37
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/RibbonDynamicProxy.java
...ibbonclientextensions/typedclient/RibbonDynamicProxy.java
+48
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Cache.java
.../ribbonclientextensions/typedclient/annotation/Cache.java
+12
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Content.java
...ibbonclientextensions/typedclient/annotation/Content.java
+11
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/GET.java
...ix/ribbonclientextensions/typedclient/annotation/GET.java
+11
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Hystrix.java
...ibbonclientextensions/typedclient/annotation/Hystrix.java
+12
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/POST.java
...x/ribbonclientextensions/typedclient/annotation/POST.java
+11
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Path.java
...x/ribbonclientextensions/typedclient/annotation/Path.java
+12
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/TemplateName.java
...clientextensions/typedclient/annotation/TemplateName.java
+12
-0
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Var.java
...ix/ribbonclientextensions/typedclient/annotation/Var.java
+12
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplateExecutorTest.java
...entextensions/typedclient/MethodTemplateExecutorTest.java
+95
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplateTest.java
...ibbonclientextensions/typedclient/MethodTemplateTest.java
+57
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/ReflectUtilTest.java
...x/ribbonclientextensions/typedclient/ReflectUtilTest.java
+36
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/RibbonDynamicProxyTest.java
...nclientextensions/typedclient/RibbonDynamicProxyTest.java
+66
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/Movie.java
...flix/ribbonclientextensions/typedclient/sample/Movie.java
+8
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/SampleBrokenTypedMovieService.java
...ons/typedclient/sample/SampleBrokenTypedMovieService.java
+19
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/SampleTypedMovieService.java
...xtensions/typedclient/sample/SampleTypedMovieService.java
+36
-0
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/SampleUntypedMovieService.java
...ensions/typedclient/sample/SampleUntypedMovieService.java
+33
-0
未找到文件。
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/Ribbon.java
浏览文件 @
895eeff5
...
...
@@ -2,6 +2,7 @@ package com.netflix.ribbonclientextensions;
import
com.netflix.ribbonclientextensions.http.HttpRequestTemplate
;
import
com.netflix.ribbonclientextensions.typedclient.RibbonDynamicProxy
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
public
final
class
Ribbon
{
...
...
@@ -14,6 +15,6 @@ public final class Ribbon {
}
public
static
<
I
,
O
,
T
>
T
from
(
Class
<
T
>
contract
,
HttpClient
<
I
,
O
>
transportClient
)
{
return
null
;
return
RibbonDynamicProxy
.
newInstance
(
contract
,
transportClient
)
;
}
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplate.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Content
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.GET
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.POST
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Path
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.TemplateName
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Var
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.List
;
import
static
java
.
lang
.
String
.*;
/**
* Extracts information from Ribbon annotated method, to automatically populate the Ribbon request template.
* A few validations are performed as well:
* - a return type must be {@link com.netflix.ribbonclientextensions.RibbonRequest}
* - HTTP method must be always specified explicitly (there are no defaults)
* - only parameter with {@link com.netflix.ribbonclientextensions.typedclient.annotation.Content} annotation is allowed
*
* @author Tomasz Bak
*/
public
class
MethodTemplate
{
public
static
enum
HttpMethod
{
GET
,
POST
}
private
static
final
MethodTemplate
[]
EMPTY_ARRAY
=
new
MethodTemplate
[]{};
private
final
String
templateName
;
private
final
HttpMethod
httpMethod
;
private
final
Method
method
;
private
final
String
path
;
private
final
String
[]
paramNames
;
private
final
int
[]
valueIdxs
;
private
final
int
contentArgPosition
;
public
MethodTemplate
(
Method
method
)
{
this
.
method
=
method
;
this
.
httpMethod
=
extractHttpMethod
();
this
.
templateName
=
extractTemplateName
();
this
.
path
=
extractPathInfo
();
Object
[]
nameIdxPair
=
extractParamNamesWithIndexes
();
this
.
paramNames
=
(
String
[])
nameIdxPair
[
0
];
this
.
valueIdxs
=
(
int
[])
nameIdxPair
[
1
];
this
.
contentArgPosition
=
extractContentArgPosition
();
verifyResultType
();
}
public
HttpMethod
getHttpMethod
()
{
return
httpMethod
;
}
public
String
getTemplateName
()
{
return
templateName
;
}
public
Method
getMethod
()
{
return
method
;
}
public
String
getPath
()
{
return
path
;
}
public
String
getParamNames
(
int
idx
)
{
return
paramNames
[
idx
];
}
public
int
getParamPosition
(
int
idx
)
{
return
valueIdxs
[
idx
];
}
public
int
getParamSize
()
{
return
paramNames
.
length
;
}
public
int
getContentArgPosition
()
{
return
contentArgPosition
;
}
public
static
<
T
>
MethodTemplate
[]
from
(
Class
<
T
>
clientInterface
)
{
List
<
MethodTemplate
>
list
=
new
ArrayList
<
MethodTemplate
>(
clientInterface
.
getMethods
().
length
);
for
(
Method
m
:
clientInterface
.
getMethods
())
{
list
.
add
(
new
MethodTemplate
(
m
));
}
return
list
.
toArray
(
EMPTY_ARRAY
);
}
private
HttpMethod
extractHttpMethod
()
{
Annotation
annotation
=
method
.
getAnnotation
(
GET
.
class
);
if
(
null
!=
annotation
)
{
return
HttpMethod
.
GET
;
}
annotation
=
method
.
getAnnotation
(
POST
.
class
);
if
(
null
!=
annotation
)
{
return
HttpMethod
.
POST
;
}
throw
new
IllegalArgumentException
(
format
(
"Method %s.%s does not specify HTTP method with @GET or @POST annotation"
,
method
.
getDeclaringClass
().
getSimpleName
(),
method
.
getName
()));
}
private
String
extractTemplateName
()
{
TemplateName
annotation
=
method
.
getAnnotation
(
TemplateName
.
class
);
return
(
annotation
!=
null
)
?
annotation
.
value
()
:
null
;
}
private
String
extractPathInfo
()
{
Path
annotation
=
method
.
getAnnotation
(
Path
.
class
);
return
(
annotation
!=
null
)
?
annotation
.
value
()
:
null
;
}
private
Object
[]
extractParamNamesWithIndexes
()
{
List
<
String
>
nameList
=
new
ArrayList
<
String
>();
List
<
Integer
>
idxList
=
new
ArrayList
<
Integer
>();
Annotation
[][]
params
=
method
.
getParameterAnnotations
();
for
(
int
i
=
0
;
i
<
params
.
length
;
i
++)
{
for
(
Annotation
a
:
params
[
i
])
{
if
(
a
.
annotationType
().
equals
(
Var
.
class
))
{
String
name
=
((
Var
)
a
).
value
();
nameList
.
add
(
name
);
idxList
.
add
(
i
);
}
}
}
int
size
=
nameList
.
size
();
String
[]
names
=
new
String
[
size
];
int
[]
idxs
=
new
int
[
size
];
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
names
[
i
]
=
nameList
.
get
(
i
);
idxs
[
i
]
=
idxList
.
get
(
i
);
}
return
new
Object
[]{
names
,
idxs
};
}
private
int
extractContentArgPosition
()
{
Annotation
[][]
params
=
method
.
getParameterAnnotations
();
int
pos
=
-
1
;
int
count
=
0
;
for
(
int
i
=
0
;
i
<
params
.
length
;
i
++)
{
for
(
Annotation
a
:
params
[
i
])
{
if
(
a
.
annotationType
().
equals
(
Content
.
class
))
{
pos
=
i
;
count
++;
}
}
}
if
(
count
>
1
)
{
throw
new
IllegalArgumentException
(
format
(
"Method %s.%s annotates multiple parameters as @Content - at most one is allowed "
,
method
.
getDeclaringClass
().
getSimpleName
(),
method
.
getName
()));
}
return
pos
;
}
private
void
verifyResultType
()
{
Class
resultType
=
method
.
getReturnType
();
if
(
resultType
.
isAssignableFrom
(
RibbonRequest
.
class
))
{
return
;
}
throw
new
IllegalArgumentException
(
format
(
"Method %s.%s must return Void or RibbonRequest<T> type not %s"
,
method
.
getDeclaringClass
().
getSimpleName
(),
method
.
getName
(),
resultType
.
getSimpleName
()));
}
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplateExecutor.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
com.netflix.ribbonclientextensions.RequestTemplate.RequestBuilder
;
import
com.netflix.ribbonclientextensions.Ribbon
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.http.HttpRequestTemplate
;
import
io.netty.buffer.ByteBuf
;
import
io.reactivex.netty.protocol.http.client.ContentSource
;
import
io.reactivex.netty.protocol.http.client.ContentSource.SingletonSource
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
import
io.reactivex.netty.protocol.http.client.RawContentSource.SingletonRawSource
;
import
java.lang.reflect.Method
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* @author Tomasz Bak
*/
public
class
MethodTemplateExecutor
<
O
>
{
private
final
MethodTemplate
methodTemplate
;
public
MethodTemplateExecutor
(
MethodTemplate
methodTemplate
)
{
this
.
methodTemplate
=
methodTemplate
;
}
public
<
I
>
RibbonRequest
<
O
>
executeFromTemplate
(
HttpClient
httpClient
,
Object
[]
args
)
{
HttpRequestTemplate
<
ByteBuf
,
ByteBuf
>
httpRequestTemplate
=
Ribbon
.
newHttpRequestTemplate
(
methodTemplate
.
getTemplateName
(),
httpClient
);
httpRequestTemplate
.
withMethod
(
methodTemplate
.
getHttpMethod
().
name
());
if
(
methodTemplate
.
getPath
()
!=
null
)
{
httpRequestTemplate
.
withUri
(
methodTemplate
.
getPath
());
}
if
(
methodTemplate
.
getContentArgPosition
()
>=
0
)
{
Object
contentValue
=
args
[
methodTemplate
.
getContentArgPosition
()];
httpRequestTemplate
.
withContentSource
(
new
SingletonSource
(
contentValue
));
}
RequestBuilder
requestBuilder
=
httpRequestTemplate
.
requestBuilder
();
int
length
=
methodTemplate
.
getParamSize
();
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
String
name
=
methodTemplate
.
getParamNames
(
i
);
Object
value
=
args
[
methodTemplate
.
getParamPosition
(
i
)];
requestBuilder
.
withValue
(
name
,
value
);
}
return
requestBuilder
.
build
();
}
public
static
<
O
>
Map
<
Method
,
MethodTemplateExecutor
<
O
>>
from
(
Class
clientInterface
)
{
Map
<
Method
,
MethodTemplateExecutor
<
O
>>
tgm
=
new
HashMap
<
Method
,
MethodTemplateExecutor
<
O
>>();
for
(
MethodTemplate
mt
:
MethodTemplate
.
from
(
clientInterface
))
{
tgm
.
put
(
mt
.
getMethod
(),
new
MethodTemplateExecutor
(
mt
));
}
return
tgm
;
}
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/ReflectUtil.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
java.lang.reflect.Method
;
import
static
java
.
lang
.
String
.*;
/**
* A collection of reflection helper methods.
*
* @author Tomasz Bak
*/
class
ReflectUtil
{
public
static
<
T
>
Method
methodByName
(
Class
<
T
>
aClass
,
String
name
)
{
for
(
Method
m
:
aClass
.
getMethods
())
{
if
(
m
.
getName
().
equals
(
name
))
{
return
m
;
}
}
return
null
;
}
public
static
Object
executeOnInstance
(
Object
object
,
Method
method
,
Object
[]
args
)
{
Method
targetMethod
=
methodByName
(
object
.
getClass
(),
method
.
getName
());
if
(
targetMethod
==
null
)
{
throw
new
IllegalArgumentException
(
format
(
"Signature of method %s is not compatible with the object %s"
,
method
.
getName
(),
object
.
getClass
().
getSimpleName
()));
}
try
{
return
targetMethod
.
invoke
(
object
,
args
);
}
catch
(
Exception
ex
)
{
throw
new
RuntimeException
(
format
(
"Failed to execute method %s on object %s"
,
method
.
getName
(),
object
.
getClass
().
getSimpleName
()),
ex
);
}
}
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/RibbonDynamicProxy.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
import
java.lang.reflect.InvocationHandler
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Proxy
;
import
java.util.Map
;
/**
* @author Tomasz Bak
*/
public
class
RibbonDynamicProxy
<
O
>
implements
InvocationHandler
{
private
final
Map
<
Method
,
MethodTemplateExecutor
<
O
>>
templateGeneratorMap
;
private
final
HttpClient
httpClient
;
public
RibbonDynamicProxy
(
Class
<
O
>
clientInterface
,
HttpClient
httpClient
)
{
this
.
httpClient
=
httpClient
;
this
.
templateGeneratorMap
=
MethodTemplateExecutor
.
from
(
clientInterface
);
}
@Override
public
Object
invoke
(
Object
proxy
,
Method
method
,
Object
[]
args
)
throws
Throwable
{
MethodTemplateExecutor
template
=
templateGeneratorMap
.
get
(
method
);
if
(
template
!=
null
)
{
return
template
.
executeFromTemplate
(
httpClient
,
args
);
}
// This must be one of the Object methods. Lets run it on the handler itself.
return
ReflectUtil
.
executeOnInstance
(
this
,
method
,
args
);
}
@Override
public
String
toString
()
{
return
"RibbonDynamicProxy{...}"
;
}
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
>
T
newInstance
(
Class
<
T
>
clientInterface
,
HttpClient
httpClient
)
{
if
(!
clientInterface
.
isInterface
())
{
throw
new
IllegalArgumentException
(
clientInterface
.
getName
()
+
" is a class not interface"
);
}
return
(
T
)
Proxy
.
newProxyInstance
(
Thread
.
currentThread
().
getContextClassLoader
(),
new
Class
[]{
clientInterface
},
new
RibbonDynamicProxy
<
T
>(
clientInterface
,
httpClient
)
);
}
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Cache.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Cache
{
public
String
key
();
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Content.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
PARAMETER
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Content
{
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/GET.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
GET
{
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Hystrix.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
TYPE
,
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Hystrix
{
public
String
name
();
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/POST.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
POST
{
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Path.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Path
{
public
String
value
()
default
""
;
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/TemplateName.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
METHOD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
TemplateName
{
public
String
value
();
}
ribbon-client-extensions/src/main/java/com/netflix/ribbonclientextensions/typedclient/annotation/Var.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
@Target
({
ElementType
.
PARAMETER
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Var
{
public
String
value
();
}
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplateExecutorTest.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
com.netflix.ribbonclientextensions.RequestTemplate.RequestBuilder
;
import
com.netflix.ribbonclientextensions.Ribbon
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.http.HttpRequestTemplate
;
import
com.netflix.ribbonclientextensions.typedclient.sample.Movie
;
import
com.netflix.ribbonclientextensions.typedclient.sample.SampleTypedMovieService
;
import
io.reactivex.netty.protocol.http.client.ContentSource
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
import
org.easymock.EasyMock
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.powermock.core.classloader.annotations.PrepareForTest
;
import
org.powermock.modules.junit4.PowerMockRunner
;
import
java.lang.reflect.Method
;
import
java.util.Map
;
import
static
com
.
netflix
.
ribbonclientextensions
.
typedclient
.
ReflectUtil
.*;
import
static
junit
.
framework
.
Assert
.*;
import
static
org
.
easymock
.
EasyMock
.*;
import
static
org
.
powermock
.
api
.
easymock
.
PowerMock
.
createMock
;
import
static
org
.
powermock
.
api
.
easymock
.
PowerMock
.*;
import
static
org
.
powermock
.
api
.
easymock
.
PowerMock
.
replay
;
/**
* @author Tomasz Bak
*/
@RunWith
(
PowerMockRunner
.
class
)
@PrepareForTest
(
Ribbon
.
class
)
public
class
MethodTemplateExecutorTest
{
@Test
public
void
testGetWithParameterRequest
()
throws
Exception
{
RibbonRequest
ribbonRequestMock
=
createMock
(
RibbonRequest
.
class
);
RequestBuilder
requestBuilderMock
=
createMock
(
RequestBuilder
.
class
);
expect
(
requestBuilderMock
.
withValue
(
"id"
,
"id123"
)).
andReturn
(
requestBuilderMock
);
expect
(
requestBuilderMock
.
build
()).
andReturn
(
ribbonRequestMock
);
HttpClient
httpClientMock
=
createMock
(
HttpClient
.
class
);
HttpRequestTemplate
httpRequestTemplateMock
=
createMock
(
HttpRequestTemplate
.
class
);
expect
(
httpRequestTemplateMock
.
withMethod
(
"GET"
)).
andReturn
(
httpRequestTemplateMock
);
expect
(
httpRequestTemplateMock
.
withUri
(
"/movies/{id}"
)).
andReturn
(
httpRequestTemplateMock
);
expect
(
httpRequestTemplateMock
.
requestBuilder
()).
andReturn
(
requestBuilderMock
);
mockStatic
(
Ribbon
.
class
);
expect
(
Ribbon
.
newHttpRequestTemplate
(
"findMovieById"
,
httpClientMock
)).
andReturn
(
httpRequestTemplateMock
);
replay
(
Ribbon
.
class
,
ribbonRequestMock
,
requestBuilderMock
,
httpClientMock
,
httpRequestTemplateMock
);
MethodTemplate
methodTemplate
=
new
MethodTemplate
(
methodByName
(
SampleTypedMovieService
.
class
,
"findMovieById"
));
MethodTemplateExecutor
generator
=
new
MethodTemplateExecutor
(
methodTemplate
);
RibbonRequest
ribbonRequest
=
generator
.
executeFromTemplate
(
httpClientMock
,
new
Object
[]{
"id123"
});
assertEquals
(
ribbonRequestMock
,
ribbonRequest
);
}
@Test
public
void
testPostWithContentParameter
()
throws
Exception
{
RibbonRequest
ribbonRequestMock
=
createMock
(
RibbonRequest
.
class
);
HttpClient
httpClientMock
=
createMock
(
HttpClient
.
class
);
RequestBuilder
requestBuilderMock
=
createMock
(
RequestBuilder
.
class
);
expect
(
requestBuilderMock
.
build
()).
andReturn
(
ribbonRequestMock
);
HttpRequestTemplate
httpRequestTemplateMock
=
createMock
(
HttpRequestTemplate
.
class
);
expect
(
httpRequestTemplateMock
.
withMethod
(
"POST"
)).
andReturn
(
httpRequestTemplateMock
);
expect
(
httpRequestTemplateMock
.
withUri
(
"/movies"
)).
andReturn
(
httpRequestTemplateMock
);
expect
(
httpRequestTemplateMock
.
withContentSource
((
ContentSource
)
EasyMock
.
anyObject
())).
andReturn
(
httpRequestTemplateMock
);
expect
(
httpRequestTemplateMock
.
requestBuilder
()).
andReturn
(
requestBuilderMock
);
mockStatic
(
Ribbon
.
class
);
expect
(
Ribbon
.
newHttpRequestTemplate
(
"registerMovie"
,
httpClientMock
)).
andReturn
(
httpRequestTemplateMock
);
replay
(
Ribbon
.
class
,
ribbonRequestMock
,
requestBuilderMock
,
httpClientMock
,
httpRequestTemplateMock
);
MethodTemplate
methodTemplate
=
new
MethodTemplate
(
methodByName
(
SampleTypedMovieService
.
class
,
"registerMovie"
));
MethodTemplateExecutor
generator
=
new
MethodTemplateExecutor
(
methodTemplate
);
RibbonRequest
ribbonRequest
=
generator
.
executeFromTemplate
(
httpClientMock
,
new
Object
[]{
new
Movie
()});
assertEquals
(
ribbonRequestMock
,
ribbonRequest
);
}
@Test
public
void
testFromFactory
()
throws
Exception
{
Map
<
Method
,
MethodTemplateExecutor
<
Object
>>
executorMap
=
MethodTemplateExecutor
.
from
(
SampleTypedMovieService
.
class
);
assertEquals
(
3
,
executorMap
.
size
());
}
}
\ No newline at end of file
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/MethodTemplateTest.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
com.netflix.ribbonclientextensions.typedclient.sample.SampleBrokenTypedMovieService
;
import
com.netflix.ribbonclientextensions.typedclient.sample.SampleTypedMovieService
;
import
org.junit.Test
;
import
static
com
.
netflix
.
ribbonclientextensions
.
typedclient
.
ReflectUtil
.*;
import
static
org
.
junit
.
Assert
.*;
/**
* @author Tomasz Bak
*/
public
class
MethodTemplateTest
{
@Test
public
void
testGetWithOneParameter
()
throws
Exception
{
MethodTemplate
template
=
new
MethodTemplate
(
methodByName
(
SampleTypedMovieService
.
class
,
"findMovieById"
));
assertEquals
(
"findMovieById"
,
template
.
getTemplateName
());
assertEquals
(
"/movies/{id}"
,
template
.
getPath
());
assertEquals
(
"id"
,
template
.
getParamNames
(
0
));
assertEquals
(
0
,
template
.
getParamPosition
(
0
));
}
@Test
public
void
testGetWithTwoParameters
()
throws
Exception
{
MethodTemplate
template
=
new
MethodTemplate
(
methodByName
(
SampleTypedMovieService
.
class
,
"findMovie"
));
assertEquals
(
"findMovie"
,
template
.
getTemplateName
());
assertEquals
(
"/movies?name={name}&author={author}"
,
template
.
getPath
());
assertEquals
(
"name"
,
template
.
getParamNames
(
0
));
assertEquals
(
0
,
template
.
getParamPosition
(
0
));
assertEquals
(
"author"
,
template
.
getParamNames
(
1
));
assertEquals
(
1
,
template
.
getParamPosition
(
1
));
}
@Test
public
void
testFromFactory
()
throws
Exception
{
MethodTemplate
[]
methodTemplates
=
MethodTemplate
.
from
(
SampleTypedMovieService
.
class
);
assertEquals
(
3
,
methodTemplates
.
length
);
}
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testDetectsInvalidResultType
()
throws
Exception
{
new
MethodTemplate
(
methodByName
(
SampleBrokenTypedMovieService
.
class
,
"returnTypeNotRibbonRequest"
));
}
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testMissingHttpMethod
()
throws
Exception
{
new
MethodTemplate
(
methodByName
(
SampleBrokenTypedMovieService
.
class
,
"missingHttpMethod"
));
}
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testMultipleContentParameters
()
throws
Exception
{
new
MethodTemplate
(
methodByName
(
SampleBrokenTypedMovieService
.
class
,
"multipleContentParameters"
));
}
}
\ No newline at end of file
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/ReflectUtilTest.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
org.junit.Test
;
import
java.lang.reflect.Method
;
import
static
junit
.
framework
.
Assert
.*;
/**
* @author Tomasz Bak
*/
public
class
ReflectUtilTest
{
@Test
public
void
testMethodByName
()
throws
Exception
{
Method
source
=
ReflectUtil
.
methodByName
(
String
.
class
,
"equals"
);
assertNotNull
(
source
);
assertEquals
(
"equals"
,
source
.
getName
());
assertNull
(
ReflectUtil
.
methodByName
(
String
.
class
,
"not_equals"
));
}
@Test
public
void
testExecuteOnInstance
()
throws
Exception
{
Method
source
=
ReflectUtil
.
methodByName
(
String
.
class
,
"equals"
);
Object
obj
=
new
Object
();
assertEquals
(
Boolean
.
TRUE
,
ReflectUtil
.
executeOnInstance
(
obj
,
source
,
new
Object
[]{
obj
}));
assertEquals
(
Boolean
.
FALSE
,
ReflectUtil
.
executeOnInstance
(
obj
,
source
,
new
Object
[]{
this
}));
}
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testExecuteNotExistingMethod
()
throws
Exception
{
Method
source
=
ReflectUtil
.
methodByName
(
String
.
class
,
"getChars"
);
ReflectUtil
.
executeOnInstance
(
new
Object
(),
source
,
new
Object
[]{});
}
}
\ No newline at end of file
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/RibbonDynamicProxyTest.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.typedclient.sample.Movie
;
import
com.netflix.ribbonclientextensions.typedclient.sample.SampleTypedMovieService
;
import
io.reactivex.netty.protocol.http.client.HttpClient
;
import
org.easymock.EasyMock
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.powermock.core.classloader.annotations.PrepareForTest
;
import
org.powermock.modules.junit4.PowerMockRunner
;
import
java.lang.reflect.Method
;
import
java.util.HashMap
;
import
java.util.Map
;
import
static
com
.
netflix
.
ribbonclientextensions
.
typedclient
.
ReflectUtil
.*;
import
static
org
.
easymock
.
EasyMock
.*;
import
static
org
.
powermock
.
api
.
easymock
.
PowerMock
.
createMock
;
import
static
org
.
powermock
.
api
.
easymock
.
PowerMock
.*;
import
static
org
.
powermock
.
api
.
easymock
.
PowerMock
.
replay
;
import
static
org
.
testng
.
Assert
.*;
/**
* @author Tomasz Bak
*/
@RunWith
(
PowerMockRunner
.
class
)
@PrepareForTest
({
RibbonDynamicProxy
.
class
,
MethodTemplateExecutor
.
class
})
public
class
RibbonDynamicProxyTest
{
@Test
(
expected
=
IllegalArgumentException
.
class
)
public
void
testAcceptsInterfaceOnly
()
throws
Exception
{
RibbonDynamicProxy
.
newInstance
(
Object
.
class
,
null
);
}
@Test
public
void
testTypedClientGetWithPathParameter
()
throws
Exception
{
HttpClient
httpClientMock
=
createMock
(
HttpClient
.
class
);
RibbonRequest
ribbonRequestMock
=
createMock
(
RibbonRequest
.
class
);
MethodTemplateExecutor
tgMock
=
createMock
(
MethodTemplateExecutor
.
class
);
expect
(
tgMock
.
executeFromTemplate
((
HttpClient
)
EasyMock
.
anyObject
(),
(
Object
[])
EasyMock
.
anyObject
())).
andReturn
(
ribbonRequestMock
);
Map
<
Method
,
MethodTemplateExecutor
<
Object
>>
tgMap
=
new
HashMap
<
Method
,
MethodTemplateExecutor
<
Object
>>();
tgMap
.
put
(
methodByName
(
SampleTypedMovieService
.
class
,
"findMovieById"
),
tgMock
);
mockStatic
(
MethodTemplateExecutor
.
class
);
expect
(
MethodTemplateExecutor
.
from
(
SampleTypedMovieService
.
class
)).
andReturn
(
tgMap
);
replay
(
MethodTemplateExecutor
.
class
,
tgMock
,
httpClientMock
,
ribbonRequestMock
);
SampleTypedMovieService
service
=
RibbonDynamicProxy
.
newInstance
(
SampleTypedMovieService
.
class
,
httpClientMock
);
RibbonRequest
<
Movie
>
ribbonMovie
=
service
.
findMovieById
(
"123"
);
assertNotNull
(
ribbonMovie
);
}
@Test
public
void
testPlainObjectInvocations
()
throws
Exception
{
SampleTypedMovieService
service
=
RibbonDynamicProxy
.
newInstance
(
SampleTypedMovieService
.
class
,
null
);
assertFalse
(
service
.
equals
(
this
));
assertEquals
(
service
.
toString
(),
"RibbonDynamicProxy{...}"
);
}
}
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/Movie.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.sample
;
/**
* @author Tomasz Bak
*/
public
class
Movie
{
}
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/SampleBrokenTypedMovieService.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.sample
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Content
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.GET
;
/**
* @author Tomasz Bak
*/
public
interface
SampleBrokenTypedMovieService
{
@GET
public
Movie
returnTypeNotRibbonRequest
();
public
Movie
missingHttpMethod
();
@GET
public
RibbonRequest
<
Void
>
multipleContentParameters
(
@Content
Movie
content1
,
@Content
Movie
content2
);
}
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/SampleTypedMovieService.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.sample
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Cache
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Content
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.GET
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Hystrix
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.POST
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Path
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.TemplateName
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Var
;
/**
* @author Tomasz Bak
*/
@Hystrix
(
name
=
"movie"
)
public
interface
SampleTypedMovieService
{
@TemplateName
(
"findMovieById"
)
@Cache
(
key
=
"movie.{id}"
)
@GET
@Path
(
"/movies/{id}"
)
RibbonRequest
<
Movie
>
findMovieById
(
@Var
(
"id"
)
String
id
);
@TemplateName
(
"findMovie"
)
@Cache
(
key
=
"movie#name={name},author={author}"
)
@GET
@Path
(
"/movies?name={name}&author={author}"
)
RibbonRequest
<
Movie
>
findMovie
(
@Var
(
"name"
)
String
name
,
@Var
(
"author"
)
String
author
);
@TemplateName
(
"registerMovie"
)
@Hystrix
(
name
=
"postMovie"
)
@POST
@Path
(
"/movies"
)
RibbonRequest
<
Void
>
registerMovie
(
@Content
Movie
movie
);
}
ribbon-client-extensions/src/test/java/com/netflix/ribbonclientextensions/typedclient/sample/SampleUntypedMovieService.java
0 → 100644
浏览文件 @
895eeff5
package
com.netflix.ribbonclientextensions.typedclient.sample
;
import
com.netflix.ribbonclientextensions.RibbonRequest
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Cache
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Content
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.GET
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Hystrix
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.POST
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Path
;
import
com.netflix.ribbonclientextensions.typedclient.annotation.Var
;
import
io.netty.buffer.ByteBuf
;
/**
* @author Tomasz Bak
*/
@Hystrix
(
name
=
"movie"
)
public
interface
SampleUntypedMovieService
{
@Cache
(
key
=
"movie.{id}"
)
@GET
@Path
(
"/movies/{id}"
)
RibbonRequest
<
ByteBuf
>
findMovieById
(
@Var
(
"id"
)
String
id
);
@Cache
(
key
=
"movie#name={name},author={author}"
)
@GET
@Path
(
"/movies?name={name}&author={author}"
)
RibbonRequest
<
ByteBuf
>
findMovie
(
@Var
(
"name"
)
String
name
,
@Var
(
"author"
)
String
author
);
@Hystrix
(
name
=
"postMovie"
)
@POST
@Path
(
"/movies"
)
RibbonRequest
<
Void
>
registerMovie
(
@Content
ByteBuf
movie
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录