add encoder, decoder and contract to feign properties, so we can override the default value with properties (#2687)

This commit is contained in:
Eko Kurniawan Khannedy
2018-02-21 02:31:03 +07:00
committed by Ryan Baxter
parent a082146715
commit 61bbca23ff
5 changed files with 114 additions and 7 deletions

View File

@@ -1131,6 +1131,9 @@ feign:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
encoder: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract
----
Default configurations can be specified in the `@EnableFeignClients` attribute `defaultConfiguration` in a similar manner as described above. The difference is that this configuration will apply to _all_ feign clients.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2018 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.
@@ -179,6 +179,18 @@ class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
builder.decode404();
}
}
if (Objects.nonNull(config.getEncoder())) {
builder.encoder(getOrInstantiate(config.getEncoder()));
}
if (Objects.nonNull(config.getDecoder())) {
builder.decoder(getOrInstantiate(config.getDecoder()));
}
if (Objects.nonNull(config.getContract())) {
builder.contract(getOrInstantiate(config.getContract()));
}
}
private <T> T getOrInstantiate(Class<T> tClass) {

View File

@@ -15,9 +15,12 @@
*/
package org.springframework.cloud.netflix.feign;
import feign.Contract;
import feign.Logger;
import feign.RequestInterceptor;
import feign.Retryer;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -93,6 +96,12 @@ public class FeignClientProperties {
private Boolean decode404;
private Class<Decoder> decoder;
private Class<Encoder> encoder;
private Class<Contract> contract;
public Logger.Level getLoggerLevel() {
return loggerLevel;
}
@@ -149,6 +158,30 @@ public class FeignClientProperties {
this.decode404 = decode404;
}
public Class<Decoder> getDecoder() {
return decoder;
}
public void setDecoder(Class<Decoder> decoder) {
this.decoder = decoder;
}
public Class<Encoder> getEncoder() {
return encoder;
}
public void setEncoder(Class<Encoder> encoder) {
this.encoder = encoder;
}
public Class<Contract> getContract() {
return contract;
}
public void setContract(Class<Contract> contract) {
this.contract = contract;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -160,13 +193,16 @@ public class FeignClientProperties {
Objects.equals(retryer, that.retryer) &&
Objects.equals(errorDecoder, that.errorDecoder) &&
Objects.equals(requestInterceptors, that.requestInterceptors) &&
Objects.equals(decode404, that.decode404);
Objects.equals(decode404, that.decode404) &&
Objects.equals(encoder, that.encoder) &&
Objects.equals(decoder, that.decoder) &&
Objects.equals(contract, that.contract);
}
@Override
public int hashCode() {
return Objects.hash(loggerLevel, connectTimeout, readTimeout, retryer,
errorDecoder, requestInterceptors, decode404);
errorDecoder, requestInterceptors, decode404, encoder, decoder, contract);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2013-2018 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.
@@ -20,6 +20,8 @@ import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.RetryableException;
import feign.Retryer;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -30,6 +32,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -38,8 +42,11 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
@@ -64,6 +71,8 @@ public class FeignClientUsingPropertiesTests {
private FeignClientFactoryBean barFactoryBean;
private FeignClientFactoryBean formFactoryBean;
public FeignClientUsingPropertiesTests() {
fooFactoryBean = new FeignClientFactoryBean();
fooFactoryBean.setName("foo");
@@ -72,6 +81,10 @@ public class FeignClientUsingPropertiesTests {
barFactoryBean = new FeignClientFactoryBean();
barFactoryBean.setName("bar");
barFactoryBean.setType(FeignClientFactoryBean.class);
formFactoryBean = new FeignClientFactoryBean();
formFactoryBean.setName("form");
formFactoryBean.setType(FeignClientFactoryBean.class);
}
public FooClient fooClient() {
@@ -84,10 +97,15 @@ public class FeignClientUsingPropertiesTests {
return barFactoryBean.feign(context).target(BarClient.class, "http://localhost:" + this.port);
}
public FormClient formClient() {
formFactoryBean.setApplicationContext(applicationContext);
return formFactoryBean.feign(context).target(FormClient.class, "http://localhost:" + this.port);
}
@Test
public void testFoo() {
String response = fooClient().foo();
assertNotNull("OK", response);
assertEquals("OK", response);
}
@Test(expected = RetryableException.class)
@@ -96,6 +114,13 @@ public class FeignClientUsingPropertiesTests {
fail("it should timeout");
}
@Test
public void testForm() {
Map<String, String> request = Collections.singletonMap("form", "Data");
String response = formClient().form(request);
assertEquals("Data", response);
}
protected interface FooClient {
@RequestMapping(method = RequestMethod.GET, value = "/foo")
@@ -108,6 +133,14 @@ public class FeignClientUsingPropertiesTests {
String bar();
}
protected interface FormClient {
@RequestMapping(value = "/form", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
String form(Map<String, String> form);
}
@Configuration
@EnableAutoConfiguration
@RestController
@@ -129,6 +162,12 @@ public class FeignClientUsingPropertiesTests {
return "OK";
}
@RequestMapping(value = "/form", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String form(HttpServletRequest request) {
return request.getParameter("form");
}
}
public static class FooRequestInterceptor implements RequestInterceptor {
@@ -161,4 +200,19 @@ public class FeignClientUsingPropertiesTests {
public static class DefaultErrorDecoder extends ErrorDecoder.Default {
}
public static class FormEncoder implements Encoder {
@Override
public void encode(Object o, Type type, RequestTemplate requestTemplate) throws EncodeException {
Map<String, String> form = (Map<String, String>) o;
StringBuilder builder = new StringBuilder();
form.forEach((key, value) -> {
builder.append(key + "=" + value + "&");
});
requestTemplate.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
requestTemplate.body(builder.toString());
}
}
}

View File

@@ -16,4 +16,6 @@ feign.client.config.foo.requestInterceptors[0]=org.springframework.cloud.netflix
feign.client.config.foo.requestInterceptors[1]=org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests.BarRequestInterceptor
feign.client.config.bar.connectTimeout=1000
feign.client.config.bar.readTimeout=1000
feign.client.config.bar.readTimeout=1000
feign.client.config.form.encoder=org.springframework.cloud.netflix.feign.FeignClientUsingPropertiesTests.FormEncoder