Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-cloud-netflix
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
spring-cloud-netflix
Commits
4fdb85e6
Commit
4fdb85e6
authored
Nov 04, 2015
by
Spencer Gibb
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #619 from jmnarloch/feign-parameter-processors
* feign-parameter-processors: Feign annotated parameter processors
parents
50efa853
31d2f655
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
376 additions
and
74 deletions
+376
-74
AnnotatedParameterProcessor.java
...work/cloud/netflix/feign/AnnotatedParameterProcessor.java
+84
-0
FeignClientsConfiguration.java
...mework/cloud/netflix/feign/FeignClientsConfiguration.java
+7
-1
PathVariableParameterProcessor.java
...flix/feign/annotation/PathVariableParameterProcessor.java
+75
-0
RequestHeaderParameterProcessor.java
...lix/feign/annotation/RequestHeaderParameterProcessor.java
+57
-0
RequestParamParameterProcessor.java
...flix/feign/annotation/RequestParamParameterProcessor.java
+57
-0
SpringMvcContract.java
...mework/cloud/netflix/feign/support/SpringMvcContract.java
+91
-67
SpringMvcContractTest.java
...rk/cloud/netflix/feign/support/SpringMvcContractTest.java
+5
-6
No files found.
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/AnnotatedParameterProcessor.java
0 → 100644
View file @
4fdb85e6
/*
* Copyright 2013-2015 the original author or authors.
*
* 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
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
java.lang.annotation.Annotation
;
import
java.util.Collection
;
import
feign.MethodMetadata
;
/**
* Feign contract method parameter processor.
*
* @author Jakub Narloch
*/
public
interface
AnnotatedParameterProcessor
{
/**
* Retrieves the processor supported annotation type.
*
* @return the annotation type
*/
Class
<?
extends
Annotation
>
getAnnotationType
();
/**
* Process the annotated parameter.
*
* @param context the parameter context
* @param annotation the annotation instance
* @return whether the parameter is http
*/
boolean
processArgument
(
AnnotatedParameterContext
context
,
Annotation
annotation
);
/**
* Specifies the parameter context.
*
* @author Jakub Narloch
*/
interface
AnnotatedParameterContext
{
/**
* Retrieves the method metadata.
*
* @return the method metadata
*/
MethodMetadata
getMethodMetadata
();
/**
* Retrieves the index of the parameter.
*
* @return the parameter index
*/
int
getParameterIndex
();
/**
* Sets the parameter name.
*
* @param name the name of the parameter
*/
void
setParameterName
(
String
name
);
/**
* Sets the template parameter.
*
* @param name the template parameter
* @param rest the existing parameter values
* @return parameters
*/
Collection
<
String
>
setTemplateParameter
(
String
name
,
Collection
<
String
>
rest
);
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsConfiguration.java
View file @
4fdb85e6
...
...
@@ -16,6 +16,9 @@
package
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.apache.http.client.HttpClient
;
import
org.springframework.beans.factory.ObjectFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
@@ -44,6 +47,9 @@ public class FeignClientsConfiguration {
@Autowired
private
ObjectFactory
<
HttpMessageConverters
>
messageConverters
;
@Autowired
(
required
=
false
)
private
List
<
AnnotatedParameterProcessor
>
parameterProcessors
=
new
ArrayList
<>();
@Bean
@ConditionalOnMissingBean
public
Decoder
feignDecoder
()
{
...
...
@@ -59,7 +65,7 @@ public class FeignClientsConfiguration {
@Bean
@ConditionalOnMissingBean
public
Contract
feignContract
()
{
return
new
SpringMvcContract
();
return
new
SpringMvcContract
(
parameterProcessors
);
}
@Configuration
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/PathVariableParameterProcessor.java
0 → 100644
View file @
4fdb85e6
/*
* Copyright 2013-2015 the original author or authors.
*
* 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
org
.
springframework
.
cloud
.
netflix
.
feign
.
annotation
;
import
java.lang.annotation.Annotation
;
import
java.util.Collection
;
import
java.util.Map
;
import
org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
feign.MethodMetadata
;
import
static
feign
.
Util
.
checkState
;
import
static
feign
.
Util
.
emptyToNull
;
/**
* {@link PathVariable} parameter processor.
*
* @author Jakub Narloch
* @see AnnotatedParameterProcessor
*/
public
class
PathVariableParameterProcessor
implements
AnnotatedParameterProcessor
{
private
static
final
Class
<
PathVariable
>
ANNOTATION
=
PathVariable
.
class
;
@Override
public
Class
<?
extends
Annotation
>
getAnnotationType
()
{
return
ANNOTATION
;
}
@Override
public
boolean
processArgument
(
AnnotatedParameterContext
context
,
Annotation
annotation
)
{
String
name
=
ANNOTATION
.
cast
(
annotation
).
value
();
checkState
(
emptyToNull
(
name
)
!=
null
,
"PathVariable annotation was empty on param %s."
,
context
.
getParameterIndex
());
context
.
setParameterName
(
name
);
MethodMetadata
data
=
context
.
getMethodMetadata
();
String
varName
=
'{'
+
name
+
'}'
;
if
(!
data
.
template
().
url
().
contains
(
varName
)
&&
!
searchMapValues
(
data
.
template
().
queries
(),
varName
)
&&
!
searchMapValues
(
data
.
template
().
headers
(),
varName
))
{
data
.
formParams
().
add
(
name
);
}
return
true
;
}
private
<
K
,
V
>
boolean
searchMapValues
(
Map
<
K
,
Collection
<
V
>>
map
,
V
search
)
{
Collection
<
Collection
<
V
>>
values
=
map
.
values
();
if
(
values
==
null
)
{
return
false
;
}
for
(
Collection
<
V
>
entry
:
values
)
{
if
(
entry
.
contains
(
search
))
{
return
true
;
}
}
return
false
;
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/RequestHeaderParameterProcessor.java
0 → 100644
View file @
4fdb85e6
/*
* Copyright 2013-2015 the original author or authors.
*
* 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
org
.
springframework
.
cloud
.
netflix
.
feign
.
annotation
;
import
java.lang.annotation.Annotation
;
import
java.util.Collection
;
import
org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor
;
import
org.springframework.web.bind.annotation.RequestHeader
;
import
feign.MethodMetadata
;
import
static
feign
.
Util
.
checkState
;
import
static
feign
.
Util
.
emptyToNull
;
/**
* {@link RequestHeader} parameter processor.
*
* @author Jakub Narloch
* @see AnnotatedParameterProcessor
*/
public
class
RequestHeaderParameterProcessor
implements
AnnotatedParameterProcessor
{
private
static
final
Class
<
RequestHeader
>
ANNOTATION
=
RequestHeader
.
class
;
@Override
public
Class
<?
extends
Annotation
>
getAnnotationType
()
{
return
ANNOTATION
;
}
@Override
public
boolean
processArgument
(
AnnotatedParameterContext
context
,
Annotation
annotation
)
{
String
name
=
ANNOTATION
.
cast
(
annotation
).
value
();
checkState
(
emptyToNull
(
name
)
!=
null
,
"RequestHeader.value() was empty on parameter %s"
,
context
.
getParameterIndex
());
context
.
setParameterName
(
name
);
MethodMetadata
data
=
context
.
getMethodMetadata
();
Collection
<
String
>
header
=
context
.
setTemplateParameter
(
name
,
data
.
template
().
headers
().
get
(
name
));
data
.
template
().
header
(
name
,
header
);
return
true
;
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/RequestParamParameterProcessor.java
0 → 100644
View file @
4fdb85e6
/*
* Copyright 2013-2015 the original author or authors.
*
* 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
org
.
springframework
.
cloud
.
netflix
.
feign
.
annotation
;
import
java.lang.annotation.Annotation
;
import
java.util.Collection
;
import
org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
feign.MethodMetadata
;
import
static
feign
.
Util
.
checkState
;
import
static
feign
.
Util
.
emptyToNull
;
/**
* {@link RequestParam} parameter processor.
*
* @author Jakub Narloch
* @see AnnotatedParameterProcessor
*/
public
class
RequestParamParameterProcessor
implements
AnnotatedParameterProcessor
{
private
static
final
Class
<
RequestParam
>
ANNOTATION
=
RequestParam
.
class
;
@Override
public
Class
<?
extends
Annotation
>
getAnnotationType
()
{
return
ANNOTATION
;
}
@Override
public
boolean
processArgument
(
AnnotatedParameterContext
context
,
Annotation
annotation
)
{
String
name
=
ANNOTATION
.
cast
(
annotation
).
value
();
checkState
(
emptyToNull
(
name
)
!=
null
,
"RequestParam.value() was empty on parameter %s"
,
context
.
getParameterIndex
());
context
.
setParameterName
(
name
);
MethodMetadata
data
=
context
.
getMethodMetadata
();
Collection
<
String
>
query
=
context
.
setTemplateParameter
(
name
,
data
.
template
().
queries
().
get
(
name
));
data
.
template
().
query
(
name
,
query
);
return
true
;
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringMvcContract.java
View file @
4fdb85e6
...
...
@@ -16,19 +16,26 @@
package
org
.
springframework
.
cloud
.
netflix
.
feign
.
support
;
import
feign.Contract
;
import
feign.MethodMetadata
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestHeader
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor
;
import
org.springframework.cloud.netflix.feign.annotation.PathVariableParameterProcessor
;
import
org.springframework.cloud.netflix.feign.annotation.RequestHeaderParameterProcessor
;
import
org.springframework.cloud.netflix.feign.annotation.RequestParamParameterProcessor
;
import
org.springframework.util.Assert
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
feign.Contract
;
import
feign.MethodMetadata
;
import
static
feign
.
Util
.
checkState
;
import
static
feign
.
Util
.
emptyToNull
;
...
...
@@ -41,6 +48,24 @@ public class SpringMvcContract extends Contract.BaseContract {
private
static
final
String
CONTENT_TYPE
=
"Content-Type"
;
private
final
Map
<
Class
<?
extends
Annotation
>,
AnnotatedParameterProcessor
>
annotatedArgumentProcessors
;
public
SpringMvcContract
()
{
this
(
Collections
.<
AnnotatedParameterProcessor
>
emptyList
());
}
public
SpringMvcContract
(
List
<
AnnotatedParameterProcessor
>
annotatedParameterProcessors
)
{
Assert
.
notNull
(
annotatedParameterProcessors
,
"Parameter processors can not be null."
);
List
<
AnnotatedParameterProcessor
>
processors
;
if
(!
annotatedParameterProcessors
.
isEmpty
())
{
processors
=
new
ArrayList
<>(
annotatedParameterProcessors
);
}
else
{
processors
=
getDefaultAnnotatedArgumentsProcessors
();
}
this
.
annotatedArgumentProcessors
=
toAnnotatedArgumentProcessorMap
(
processors
);
}
@Override
public
MethodMetadata
parseAndValidateMetadata
(
Class
<?>
targetType
,
Method
method
)
{
MethodMetadata
md
=
super
.
parseAndValidateMetadata
(
targetType
,
method
);
...
...
@@ -109,6 +134,7 @@ public class SpringMvcContract extends Contract.BaseContract {
parseHeaders
(
data
,
method
,
methodMapping
);
}
private
void
checkAtMostOne
(
Method
method
,
Object
[]
values
,
String
fieldName
)
{
checkState
(
values
!=
null
&&
(
values
.
length
==
0
||
values
.
length
==
1
),
"Method %s can only contain at most 1 %s field. Found: %s"
,
...
...
@@ -123,72 +149,19 @@ public class SpringMvcContract extends Contract.BaseContract {
}
@Override
protected
boolean
processAnnotationsOnParameter
(
MethodMetadata
data
,
Annotation
[]
annotations
,
int
paramIndex
)
{
protected
boolean
processAnnotationsOnParameter
(
MethodMetadata
data
,
Annotation
[]
annotations
,
int
paramIndex
)
{
boolean
isHttpAnnotation
=
false
;
// TODO: support spring parameter annotations?
for
(
Annotation
parameterAnnotation
:
annotations
)
{
if
(
parameterAnnotation
instanceof
PathVariable
)
{
String
name
=
PathVariable
.
class
.
cast
(
parameterAnnotation
).
value
();
checkState
(
emptyToNull
(
name
)
!=
null
,
"PathVariable annotation was empty on param %s."
,
paramIndex
);
nameParam
(
data
,
name
,
paramIndex
);
isHttpAnnotation
=
true
;
String
varName
=
'{'
+
name
+
'}'
;
if
(
data
.
template
().
url
().
indexOf
(
varName
)
==
-
1
&&
!
searchMapValues
(
data
.
template
().
queries
(),
varName
)
&&
!
searchMapValues
(
data
.
template
().
headers
(),
varName
))
{
data
.
formParams
().
add
(
name
);
}
}
else
if
(
parameterAnnotation
instanceof
RequestParam
)
{
String
name
=
RequestParam
.
class
.
cast
(
parameterAnnotation
).
value
();
checkState
(
emptyToNull
(
name
)
!=
null
,
"QueryParam.value() was empty on parameter %s"
,
paramIndex
);
Collection
<
String
>
query
=
addTemplatedParam
(
data
.
template
().
queries
()
.
get
(
name
),
name
);
data
.
template
().
query
(
name
,
query
);
nameParam
(
data
,
name
,
paramIndex
);
isHttpAnnotation
=
true
;
}
else
if
(
parameterAnnotation
instanceof
RequestHeader
)
{
String
name
=
RequestHeader
.
class
.
cast
(
parameterAnnotation
).
value
();
checkState
(
emptyToNull
(
name
)
!=
null
,
"HeaderParam.value() was empty on parameter %s"
,
paramIndex
);
Collection
<
String
>
header
=
addTemplatedParam
(
data
.
template
().
headers
()
.
get
(
name
),
name
);
data
.
template
().
header
(
name
,
header
);
nameParam
(
data
,
name
,
paramIndex
);
isHttpAnnotation
=
true
;
}
// TODO
/*
* else if (annotationType == FormParam.class) { String name =
* FormParam.class.cast(parameterAnnotation).value();
* checkState(emptyToNull(name) != null,
* "FormParam.value() was empty on parameter %s", paramIndex);
* data.formParams().add(name); nameParam(data, name, paramIndex);
* isHttpAnnotation = true; }
*/
AnnotatedParameterProcessor
.
AnnotatedParameterContext
context
=
new
SimpleAnnotatedParameterContext
(
data
,
paramIndex
);
for
(
Annotation
parameterAnnotation
:
annotations
)
{
AnnotatedParameterProcessor
processor
=
annotatedArgumentProcessors
.
get
(
parameterAnnotation
.
annotationType
());
isHttpAnnotation
|=
processor
.
processArgument
(
context
,
parameterAnnotation
);
}
return
isHttpAnnotation
;
}
private
<
K
,
V
>
boolean
searchMapValues
(
Map
<
K
,
Collection
<
V
>>
map
,
V
search
)
{
Collection
<
Collection
<
V
>>
values
=
map
.
values
();
if
(
values
==
null
)
{
return
false
;
}
for
(
Collection
<
V
>
entry
:
values
)
{
if
(
entry
.
contains
(
search
))
{
return
true
;
}
}
return
false
;
}
private
void
parseProduces
(
MethodMetadata
md
,
Method
method
,
RequestMapping
annotation
)
{
checkAtMostOne
(
method
,
annotation
.
produces
(),
"produces"
);
String
[]
serverProduces
=
annotation
.
produces
();
...
...
@@ -220,4 +193,55 @@ public class SpringMvcContract extends Contract.BaseContract {
}
}
private
Map
<
Class
<?
extends
Annotation
>,
AnnotatedParameterProcessor
>
toAnnotatedArgumentProcessorMap
(
List
<
AnnotatedParameterProcessor
>
processors
)
{
Map
<
Class
<?
extends
Annotation
>,
AnnotatedParameterProcessor
>
result
=
new
HashMap
<>();
for
(
AnnotatedParameterProcessor
processor
:
processors
)
{
result
.
put
(
processor
.
getAnnotationType
(),
processor
);
}
return
result
;
}
private
List
<
AnnotatedParameterProcessor
>
getDefaultAnnotatedArgumentsProcessors
()
{
List
<
AnnotatedParameterProcessor
>
annotatedArgumentResolvers
=
new
ArrayList
<>();
annotatedArgumentResolvers
.
add
(
new
PathVariableParameterProcessor
());
annotatedArgumentResolvers
.
add
(
new
RequestParamParameterProcessor
());
annotatedArgumentResolvers
.
add
(
new
RequestHeaderParameterProcessor
());
return
annotatedArgumentResolvers
;
}
private
class
SimpleAnnotatedParameterContext
implements
AnnotatedParameterProcessor
.
AnnotatedParameterContext
{
private
final
MethodMetadata
methodMetadata
;
private
final
int
parameterIndex
;
public
SimpleAnnotatedParameterContext
(
MethodMetadata
methodMetadata
,
int
parameterIndex
)
{
this
.
methodMetadata
=
methodMetadata
;
this
.
parameterIndex
=
parameterIndex
;
}
@Override
public
MethodMetadata
getMethodMetadata
()
{
return
methodMetadata
;
}
@Override
public
int
getParameterIndex
()
{
return
parameterIndex
;
}
@Override
public
void
setParameterName
(
String
name
)
{
nameParam
(
methodMetadata
,
name
,
parameterIndex
);
}
@Override
public
Collection
<
String
>
setTemplateParameter
(
String
name
,
Collection
<
String
>
rest
)
{
return
addTemplatedParam
(
rest
,
name
);
}
}
}
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringMvcContractTest.java
View file @
4fdb85e6
package
org
.
springframework
.
cloud
.
netflix
.
feign
.
support
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
java.lang.reflect.Method
;
import
lombok.AllArgsConstructor
;
import
lombok.NoArgsConstructor
;
import
lombok.ToString
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.http.MediaType
;
...
...
@@ -22,6 +16,11 @@ import org.springframework.web.bind.annotation.RequestParam;
import
com.fasterxml.jackson.annotation.JsonAutoDetect
;
import
feign.MethodMetadata
;
import
lombok.AllArgsConstructor
;
import
lombok.NoArgsConstructor
;
import
lombok.ToString
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* @author chadjaros
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment