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
83caebf3
Unverified
Commit
83caebf3
authored
May 06, 2016
by
Spencer Gibb
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #983 from venilnoronha/issue-966-fix
* issue-966-fix: Adds path parameter to @FeignClient.
parents
654ea709
d3cba4d8
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
230 additions
and
4 deletions
+230
-4
FeignClient.java
.../org/springframework/cloud/netflix/feign/FeignClient.java
+9
-1
FeignClientFactoryBean.java
...framework/cloud/netflix/feign/FeignClientFactoryBean.java
+20
-2
FeignClientsRegistrar.java
...gframework/cloud/netflix/feign/FeignClientsRegistrar.java
+17
-1
FeignRibbonClientPathTests.java
...loud/netflix/feign/ribbon/FeignRibbonClientPathTests.java
+184
-0
No files found.
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
View file @
83caebf3
/*
* Copyright 2013-201
5
the original author or authors.
* Copyright 2013-201
6
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.
...
...
@@ -31,6 +31,7 @@ import org.springframework.core.annotation.AliasFor;
* using a <code>@RibbonClient</code> with the same name (i.e. value) as the feign client.
*
* @author Spencer Gibb
* @author Venil Noronha
*/
@Target
(
ElementType
.
TYPE
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
...
...
@@ -81,4 +82,11 @@ public @interface FeignClient {
* implement the interface annotated by this annotation and be a valid spring bean.
*/
Class
<?>
fallback
()
default
void
.
class
;
/**
* Path prefix to be used by all method-level mappings. Can be used with or without
* <code>@RibbonClient</code>.
*/
String
path
()
default
""
;
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
View file @
83caebf3
/*
* Copyright 2013-201
5
the original author or authors.
* Copyright 2013-201
6
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.
...
...
@@ -44,6 +44,7 @@ import lombok.EqualsAndHashCode;
/**
* @author Spencer Gibb
* @author Venil Noronha
*/
@Data
@EqualsAndHashCode
(
callSuper
=
false
)
...
...
@@ -70,6 +71,8 @@ class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
private
String
url
;
private
String
path
;
private
boolean
decode404
;
private
ApplicationContext
applicationContext
;
...
...
@@ -170,14 +173,29 @@ class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
else
{
url
=
this
.
name
;
}
url
+=
cleanPath
();
return
loadBalance
(
builder
,
context
,
new
HardCodedTarget
<>(
this
.
type
,
this
.
name
,
url
));
}
if
(
StringUtils
.
hasText
(
this
.
url
)
&&
!
this
.
url
.
startsWith
(
"http"
))
{
this
.
url
=
"http://"
+
this
.
url
;
}
String
url
=
this
.
url
+
cleanPath
();
return
targeter
.
target
(
this
,
builder
,
context
,
new
HardCodedTarget
<>(
this
.
type
,
this
.
name
,
this
.
url
));
this
.
type
,
this
.
name
,
url
));
}
private
String
cleanPath
()
{
String
path
=
this
.
path
.
trim
();
if
(
StringUtils
.
hasLength
(
path
))
{
if
(!
path
.
startsWith
(
"/"
))
{
path
=
"/"
+
path
;
}
if
(
path
.
endsWith
(
"/"
))
{
path
=
path
.
substring
(
0
,
path
.
length
()
-
1
);
}
}
return
path
;
}
@Override
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
View file @
83caebf3
/*
* Copyright 2013-201
5
the original author or authors.
* Copyright 2013-201
6
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.
...
...
@@ -55,6 +55,7 @@ import org.springframework.util.StringUtils;
/**
* @author Spencer Gibb
* @author Jakub Narloch
* @author Venil Noronha
*/
public
class
FeignClientsRegistrar
implements
ImportBeanDefinitionRegistrar
,
ResourceLoaderAware
,
BeanClassLoaderAware
{
...
...
@@ -171,6 +172,7 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
.
genericBeanDefinition
(
FeignClientFactoryBean
.
class
);
validate
(
attributes
);
definition
.
addPropertyValue
(
"url"
,
getUrl
(
attributes
));
definition
.
addPropertyValue
(
"path"
,
getPath
(
attributes
));
String
name
=
getName
(
attributes
);
definition
.
addPropertyValue
(
"name"
,
name
);
definition
.
addPropertyValue
(
"type"
,
className
);
...
...
@@ -247,6 +249,20 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
return
url
;
}
private
String
getPath
(
Map
<
String
,
Object
>
attributes
)
{
String
path
=
resolve
((
String
)
attributes
.
get
(
"path"
));
if
(
StringUtils
.
hasText
(
path
))
{
path
=
path
.
trim
();
if
(!
path
.
startsWith
(
"/"
))
{
path
=
"/"
+
path
;
}
if
(
path
.
endsWith
(
"/"
))
{
path
=
path
.
substring
(
0
,
path
.
length
()
-
1
);
}
}
return
path
;
}
protected
ClassPathScanningCandidateComponentProvider
getScanner
()
{
return
new
ClassPathScanningCandidateComponentProvider
(
false
)
{
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/ribbon/FeignRibbonClientPathTests.java
0 → 100644
View file @
83caebf3
/*
* Copyright 2016 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
.
ribbon
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.test.SpringApplicationConfiguration
;
import
org.springframework.boot.test.WebIntegrationTest
;
import
org.springframework.cloud.netflix.feign.EnableFeignClients
;
import
org.springframework.cloud.netflix.feign.FeignClient
;
import
org.springframework.cloud.netflix.ribbon.RibbonClient
;
import
org.springframework.cloud.netflix.ribbon.StaticServerList
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.test.annotation.DirtiesContext
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RestController
;
import
com.netflix.loadbalancer.Server
;
import
com.netflix.loadbalancer.ServerList
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
/**
* @author Venil Noronha
*/
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringApplicationConfiguration
(
classes
=
FeignRibbonClientPathTests
.
Application
.
class
)
@WebIntegrationTest
(
randomPort
=
true
,
value
=
{
"spring.application.name=feignribbonclientpathtest"
,
"feign.okhttp.enabled=false"
,
"feign.httpclient.enabled=false"
,
"feign.hystrix.enabled=false"
,
"test.path.prefix=/base/path"
// For pathWithPlaceholder test
}
)
@DirtiesContext
public
class
FeignRibbonClientPathTests
{
@Value
(
"${local.server.port}"
)
private
int
port
=
0
;
@Autowired
private
TestClient1
testClient1
;
@Autowired
private
TestClient2
testClient2
;
@Autowired
private
TestClient3
testClient3
;
@Autowired
private
TestClient4
testClient4
;
@Autowired
private
TestClient5
testClient5
;
protected
interface
TestClient
{
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hello"
)
Hello
getHello
();
}
@FeignClient
(
name
=
"localapp"
,
path
=
"/base/path"
)
protected
interface
TestClient1
extends
TestClient
{
}
@FeignClient
(
name
=
"localapp"
,
path
=
"base/path"
)
protected
interface
TestClient2
extends
TestClient
{
}
@FeignClient
(
name
=
"localapp"
,
path
=
"base/path/"
)
protected
interface
TestClient3
extends
TestClient
{
}
@FeignClient
(
name
=
"localapp"
,
path
=
"/base/path/"
)
protected
interface
TestClient4
extends
TestClient
{
}
@FeignClient
(
name
=
"localapp"
,
path
=
"${test.path.prefix}"
)
protected
interface
TestClient5
extends
TestClient
{
}
@Configuration
@EnableAutoConfiguration
@RestController
@RequestMapping
(
"/base/path"
)
@EnableFeignClients
(
clients
=
{
TestClient1
.
class
,
TestClient2
.
class
,
TestClient3
.
class
,
TestClient4
.
class
,
TestClient5
.
class
})
@RibbonClient
(
name
=
"localapp"
,
configuration
=
LocalRibbonClientConfiguration
.
class
)
public
static
class
Application
{
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hello"
)
public
Hello
getHello
()
{
return
new
Hello
(
"hello world"
);
}
public
static
void
main
(
String
[]
args
)
throws
InterruptedException
{
new
SpringApplicationBuilder
(
Application
.
class
).
properties
(
"spring.application.name=feignribbonclientpathtest"
,
"management.contextPath=/admin"
).
run
(
args
);
}
}
@Test
public
void
pathWithLeadingButNotTrailingSlash
()
{
testClientPath
(
this
.
testClient1
);
}
@Test
public
void
pathWithoutLeadingAndTrailingSlash
()
{
testClientPath
(
this
.
testClient2
);
}
@Test
public
void
pathWithoutLeadingButTrailingSlash
()
{
testClientPath
(
this
.
testClient3
);
}
@Test
public
void
pathWithLeadingAndTrailingSlash
()
{
testClientPath
(
this
.
testClient4
);
}
@Test
public
void
pathWithPlaceholder
()
{
testClientPath
(
this
.
testClient5
);
}
private
void
testClientPath
(
TestClient
testClient
)
{
Hello
hello
=
testClient
.
getHello
();
assertNotNull
(
"Object returned was null"
,
hello
);
assertEquals
(
"Response object value didn't match"
,
"hello world"
,
hello
.
getMessage
());
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public
static
class
Hello
{
private
String
message
;
}
@Configuration
public
static
class
LocalRibbonClientConfiguration
{
@Value
(
"${local.server.port}"
)
private
int
port
=
0
;
@Bean
public
ServerList
<
Server
>
ribbonServerList
()
{
return
new
StaticServerList
<>(
new
Server
(
"localhost"
,
this
.
port
));
}
}
}
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