Skip to content

Commit 09c5852

Browse files
Pierre Lakrebpilak
Pierre Lakreb
authored andcommitted
Add @QueryMap mapEncoder attribute
* use `mapEncoder` attribute at method level for what encoder to use * still use builder `QueryMapEncoder` if no attribute specified
1 parent 26dadc2 commit 09c5852

File tree

7 files changed

+82
-6
lines changed

7 files changed

+82
-6
lines changed

core/src/main/java/feign/BaseBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public abstract class BaseBuilder<B extends BaseBuilder<B>> {
4343
protected Encoder encoder = new Encoder.Default();
4444
protected Decoder decoder = new Decoder.Default();
4545
protected boolean closeAfterDecode = true;
46-
protected QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
46+
protected QueryMapEncoder queryMapEncoder = QueryMap.MapEncoder.FIELD.instance();
4747
protected ErrorDecoder errorDecoder = new ErrorDecoder.Default();
4848
protected Options options = new Options();
4949
protected InvocationHandlerFactory invocationHandlerFactory =

core/src/main/java/feign/Contract.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ public Default() {
315315
checkState(data.queryMapIndex() == null,
316316
"QueryMap annotation was present on multiple parameters.");
317317
data.queryMapIndex(paramIndex);
318+
data.queryMapEncoder(queryMap.mapEncoder().instance());
318319
});
319320
super.registerParameterAnnotation(HeaderMap.class, (queryMap, data, paramIndex) -> {
320321
checkState(data.headerMapIndex() == null,

core/src/main/java/feign/MethodMetadata.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public final class MethodMetadata implements Serializable {
2929
private Integer bodyIndex;
3030
private Integer headerMapIndex;
3131
private Integer queryMapIndex;
32+
private QueryMapEncoder queryMapEncoder;
3233
private boolean alwaysEncodeBody;
3334
private transient Type bodyType;
3435
private final RequestTemplate template = new RequestTemplate();
@@ -109,6 +110,15 @@ public MethodMetadata queryMapIndex(Integer queryMapIndex) {
109110
return this;
110111
}
111112

113+
public QueryMapEncoder queryMapEncoder() {
114+
return queryMapEncoder;
115+
}
116+
117+
public MethodMetadata queryMapEncoder(QueryMapEncoder queryMapEncoder) {
118+
this.queryMapEncoder = queryMapEncoder;
119+
return this;
120+
}
121+
112122
@Experimental
113123
public boolean alwaysEncodeBody() {
114124
return alwaysEncodeBody;

core/src/main/java/feign/QueryMap.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import java.lang.annotation.Retention;
1717
import java.util.List;
1818
import java.util.Map;
19+
import feign.querymap.BeanQueryMapEncoder;
20+
import feign.querymap.FieldQueryMapEncoder;
1921
import static java.lang.annotation.ElementType.PARAMETER;
2022
import static java.lang.annotation.RetentionPolicy.RUNTIME;
2123

@@ -70,4 +72,26 @@
7072
* @deprecated
7173
*/
7274
boolean encoded() default false;
75+
76+
/**
77+
* Specifies the QueryMapEncoder implementation to use to transform DTO into query map.
78+
*
79+
* @return the enum containing the instance of QueryMapEncoder
80+
*/
81+
MapEncoder mapEncoder() default MapEncoder.DEFAULT;
82+
83+
public enum MapEncoder {
84+
// the latter DEFAULT will use BaseBuilder instance
85+
BEAN(new BeanQueryMapEncoder()), FIELD(new FieldQueryMapEncoder()), DEFAULT(null);
86+
87+
private QueryMapEncoder mapEncoder;
88+
89+
private MapEncoder(QueryMapEncoder mapEncoder) {
90+
this.mapEncoder = mapEncoder;
91+
}
92+
93+
public QueryMapEncoder instance() {
94+
return mapEncoder;
95+
}
96+
}
7397
}

core/src/main/java/feign/RequestTemplateFactoryResolver.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,26 +108,28 @@ public RequestTemplate create(Object[] argv) {
108108
// add query map parameters after initial resolve so that they take
109109
// precedence over any predefined values
110110
Object value = argv[metadata.queryMapIndex()];
111-
Map<String, Object> queryMap = toQueryMap(value);
111+
Map<String, Object> queryMap = toQueryMap(value, metadata.queryMapEncoder());
112112
template = addQueryMapQueryParameters(queryMap, template);
113113
}
114114

115115
if (metadata.headerMapIndex() != null) {
116116
// add header map parameters for a resolution of the user pojo object
117117
Object value = argv[metadata.headerMapIndex()];
118-
Map<String, Object> headerMap = toQueryMap(value);
118+
Map<String, Object> headerMap = toQueryMap(value, metadata.queryMapEncoder());
119119
template = addHeaderMapHeaders(headerMap, template);
120120
}
121121

122122
return template;
123123
}
124124

125-
private Map<String, Object> toQueryMap(Object value) {
125+
private Map<String, Object> toQueryMap(Object value, QueryMapEncoder queryMapEncoder) {
126126
if (value instanceof Map) {
127127
return (Map<String, Object>) value;
128128
}
129129
try {
130-
return queryMapEncoder.encode(value);
130+
// encode with @QueryMap annotation if exists otherwise with the one from this resolver
131+
return queryMapEncoder != null ? queryMapEncoder.encode(value)
132+
: this.queryMapEncoder.encode(value);
131133
} catch (EncodeException e) {
132134
throw new IllegalStateException(e);
133135
}

core/src/test/java/feign/ChildPojo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
class ParentPojo {
1717
public String parentPublicProperty;
1818
protected String parentProtectedProperty;
19+
private String parentPrivatePropertyAlteredByGetter;
20+
21+
public String getParentPrivatePropertyAlteredByGetter() {
22+
return parentPrivatePropertyAlteredByGetter + "FromGetter";
23+
}
24+
25+
public void setParentPrivatePropertyAlteredByGetter(String parentPrivatePropertyAlteredByGetter) {
26+
this.parentPrivatePropertyAlteredByGetter = parentPrivatePropertyAlteredByGetter;
27+
}
1928

2029
public String getParentPublicProperty() {
2130
return parentPublicProperty;

core/src/test/java/feign/FeignTest.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.google.gson.Gson;
1717
import com.google.gson.reflect.TypeToken;
1818
import feign.Feign.ResponseMappingDecoder;
19+
import feign.QueryMap.MapEncoder;
1920
import feign.Request.HttpMethod;
2021
import feign.Target.HardCodedTarget;
2122
import feign.querymap.BeanQueryMapEncoder;
@@ -916,14 +917,39 @@ public void queryMap_with_child_pojo() throws Exception {
916917
childPojo.setChildPrivateProperty("first");
917918
childPojo.setParentProtectedProperty("second");
918919
childPojo.setParentPublicProperty("third");
920+
childPojo.setParentPrivatePropertyAlteredByGetter("fourth");
919921

920922
server.enqueue(new MockResponse());
921923
api.queryMapPropertyInheritence(childPojo);
922924
assertThat(server.takeRequest())
923925
.hasQueryParams(
924926
"parentPublicProperty=third",
925927
"parentProtectedProperty=second",
926-
"childPrivateProperty=first");
928+
"childPrivateProperty=first",
929+
"parentPrivatePropertyAlteredByGetter=fourth");
930+
}
931+
932+
@Test
933+
public void queryMap_with_child_pojo_altered_by_getter_while_using_overriding_encoder()
934+
throws Exception {
935+
TestInterface api = new TestInterfaceBuilder()
936+
.queryMapEndcoder(new FieldQueryMapEncoder())
937+
.target("http://localhost:" + server.getPort());
938+
939+
ChildPojo childPojo = new ChildPojo();
940+
childPojo.setChildPrivateProperty("first");
941+
childPojo.setParentProtectedProperty("second");
942+
childPojo.setParentPublicProperty("third");
943+
childPojo.setParentPrivatePropertyAlteredByGetter("fourth");
944+
945+
server.enqueue(new MockResponse());
946+
api.queryMapPropertyInheritenceWithBeanMapEncoder(childPojo);
947+
assertThat(server.takeRequest())
948+
.hasQueryParams(
949+
"parentPublicProperty=third",
950+
"parentProtectedProperty=second",
951+
"childPrivateProperty=first",
952+
"parentPrivatePropertyAlteredByGetter=fourthFromGetter");
927953
}
928954

929955
@Test
@@ -1084,6 +1110,10 @@ void queryMapWithQueryParams(@Param("name") String name,
10841110
@RequestLine("GET /")
10851111
void queryMapPropertyPojo(@QueryMap PropertyPojo object);
10861112

1113+
@RequestLine("GET /")
1114+
void queryMapPropertyInheritenceWithBeanMapEncoder(@QueryMap(
1115+
mapEncoder = MapEncoder.BEAN) ChildPojo object);
1116+
10871117
@RequestLine("GET /")
10881118
void queryMapPropertyInheritence(@QueryMap ChildPojo object);
10891119

0 commit comments

Comments
 (0)