-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add @QueryMap mapEncoder
attribute
#2098
Conversation
e318408
to
a56de3c
Compare
a56de3c
to
6975a20
Compare
Can you give project team edit access so I can rebase this branch and get CI rinnung? |
I guess this is done |
09c5852
to
a77998b
Compare
a77998b
to
b0506d3
Compare
b0506d3
to
3ad949c
Compare
* use `mapEncoder` attribute at method level for what encoder to use * still use builder `QueryMapEncoder` if no attribute specified
3ad949c
to
8a2c298
Compare
WalkthroughThis pull request introduces a flexible way to encode query parameters in Feign. It adds a new Changes
TipsChat with CodeRabbit Bot (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 3
Files selected for processing (7)
- core/src/main/java/feign/BaseBuilder.java (1 hunks)
- core/src/main/java/feign/Contract.java (1 hunks)
- core/src/main/java/feign/MethodMetadata.java (2 hunks)
- core/src/main/java/feign/QueryMap.java (2 hunks)
- core/src/main/java/feign/RequestTemplateFactoryResolver.java (1 hunks)
- core/src/test/java/feign/ChildPojo.java (1 hunks)
- core/src/test/java/feign/FeignTest.java (3 hunks)
Additional comments (Suppressed): 12
core/src/test/java/feign/ChildPojo.java (1)
- 16-30: The new private property
parentPrivatePropertyAlteredByGetter
and its getter method could potentially introduce a side effect when accessed, as it appends "FromGetter" to the returned value. Ensure that this behavior is intended and does not cause unexpected results in the rest of your codebase.- return parentPrivatePropertyAlteredByGetter + "FromGetter"; + return parentPrivatePropertyAlteredByGetter;core/src/main/java/feign/BaseBuilder.java (1)
- 47-47: The default
QueryMapEncoder
has been changed fromFieldQueryMapEncoder
toQueryMap.MapEncoder.FIELD.instance()
. Ensure that this change does not affect the existing functionality whereFieldQueryMapEncoder
was expected as the default encoder.- protected QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder(); + protected QueryMapEncoder queryMapEncoder = QueryMap.MapEncoder.FIELD.instance();core/src/main/java/feign/Contract.java (2)
315-318: The new code introduces a call to
queryMap.mapEncoder().instance()
. Ensure that themapEncoder()
method and theinstance()
method are properly defined and return the expected types. Also, verify that theinstance()
method does not have any side effects that could affect the program's behavior.320-321: No issues found in these lines. The changes seem to be consistent with the existing codebase and follow the same pattern as previous implementations.
core/src/main/java/feign/MethodMetadata.java (1)
- 29-35: The addition of
QueryMapEncoder queryMapEncoder;
is a good approach to allow more granular control over query map encoding strategies. However, please ensure that this new field is properly serialized and deserialized if theMethodMetadata
object needs to be passed across different JVMs or stored for later use, as the class implementsSerializable
.core/src/main/java/feign/QueryMap.java (1)
- 72-74: The
encoded
attribute is marked as deprecated. Ensure that this change does not break existing functionality where theencoded
attribute is used.core/src/main/java/feign/RequestTemplateFactoryResolver.java (2)
108-112: The changes here are introducing a new way to encode the query map parameters using the
queryMapEncoder
from the method metadata. This allows for more granular control over the encoding strategy at the method level.115-119: Similar to the query map parameters, the header map parameters are also being encoded using the
queryMapEncoder
from the method metadata. However, it seems odd to use aqueryMapEncoder
for headers. Please verify if this is intended or if a separate encoder should be used for headers.core/src/test/java/feign/FeignTest.java (4)
16-22: The import statement for
feign.QueryMap.MapEncoder
is added to support the new feature of specifying aQueryMapEncoder
at the method level. This change aligns with the goals of the PR.921-933: This test case verifies that the query parameters are correctly formed when using a
ChildPojo
object with thequeryMapPropertyInheritence
method. The expected behavior is that all properties (public, protected, and private) should be included in the query parameters. The test case seems to cover this scenario adequately.936-957: This test case checks the functionality of the new attribute
mapEncoder
in the@QueryMap
annotation. It uses aFieldQueryMapEncoder
as the encoder and expects the query parameters to include all properties (public, protected, and private), with the private property altered by its getter method. This test case provides good coverage for the new feature introduced in this PR.1232-1241: These changes reflect the addition of a new method
queryMapPropertyInheritenceWithBeanMapEncoder
in theTestInterface
. This method uses the newmapEncoder
attribute in the@QueryMap
annotation to specify aBEAN
encoder. This change is consistent with the PR's goal of allowing more granular control over query map encoding strategies.
public QueryMapEncoder queryMapEncoder() { | ||
return queryMapEncoder; | ||
} | ||
|
||
public MethodMetadata queryMapEncoder(QueryMapEncoder queryMapEncoder) { | ||
this.queryMapEncoder = queryMapEncoder; | ||
return this; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The getter and setter methods for queryMapEncoder
are correctly implemented. However, it would be beneficial to add null checks in the setter method to prevent potential NullPointerException
s.
public MethodMetadata queryMapEncoder(QueryMapEncoder queryMapEncoder) {
+ if (queryMapEncoder == null) {
+ throw new IllegalArgumentException("QueryMapEncoder cannot be null");
+ }
this.queryMapEncoder = queryMapEncoder;
return this;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
queryMapEncoder is nullable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pilak Thank you for your clarification. If queryMapEncoder
is indeed nullable, then the null check isn't necessary. However, it's important to ensure that any code using this setter method handles the potential null value appropriately to avoid NullPointerException
s. Here's the updated code:
public MethodMetadata queryMapEncoder(QueryMapEncoder queryMapEncoder) {
this.queryMapEncoder = queryMapEncoder;
return this;
}
Please make sure to handle the null case wherever this method is used.
/** | ||
* Specifies the QueryMapEncoder implementation to use to transform DTO into query map. | ||
* | ||
* @return the enum containing the instance of QueryMapEncoder | ||
*/ | ||
MapEncoder mapEncoder() default MapEncoder.DEFAULT; | ||
|
||
public enum MapEncoder { | ||
// the latter DEFAULT will use BaseBuilder instance | ||
BEAN(new BeanQueryMapEncoder()), FIELD(new FieldQueryMapEncoder()), DEFAULT(null); | ||
|
||
private QueryMapEncoder mapEncoder; | ||
|
||
private MapEncoder(QueryMapEncoder mapEncoder) { | ||
this.mapEncoder = mapEncoder; | ||
} | ||
|
||
public QueryMapEncoder instance() { | ||
return mapEncoder; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new mapEncoder
attribute and MapEncoder
enum are introduced to specify the QueryMapEncoder
implementation at the method level. This is a good improvement for more granular control over query map encoding strategies.
MapEncoder mapEncoder() default MapEncoder.DEFAULT;
public enum MapEncoder {
BEAN(new BeanQueryMapEncoder()), FIELD(new FieldQueryMapEncoder()), DEFAULT(null);
private QueryMapEncoder mapEncoder;
private MapEncoder(QueryMapEncoder mapEncoder) {
this.mapEncoder = mapEncoder;
}
public QueryMapEncoder instance() {
return mapEncoder;
}
}
However, it's important to ensure that the DEFAULT
value of MapEncoder
is handled correctly in the codebase where mapEncoder().instance()
is called, as it could potentially return null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this issue is correctly handled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pilak That's great to hear! It's crucial to handle potential null values to prevent unexpected NullPointerExceptions. If the DEFAULT
case is properly handled in the codebase, this change should provide a more flexible and granular control over query map encoding strategies. Good job on addressing this concern!
private Map<String, Object> toQueryMap(Object value, QueryMapEncoder queryMapEncoder) { | ||
if (value instanceof Map) { | ||
return (Map<String, Object>) value; | ||
} | ||
try { | ||
return queryMapEncoder.encode(value); | ||
// encode with @QueryMap annotation if exists otherwise with the one from this resolver | ||
return queryMapEncoder != null ? queryMapEncoder.encode(value) | ||
: this.queryMapEncoder.encode(value); | ||
} catch (EncodeException e) { | ||
throw new IllegalStateException(e); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change introduces a fallback mechanism for encoding values into a query map. If a specific QueryMapEncoder
is provided in the method metadata, it will be used; otherwise, the default encoder from the resolver will be used. This provides flexibility and allows for different encoding strategies on a per-method basis.
- return queryMapEncoder.encode(value);
+ return queryMapEncoder != null ? queryMapEncoder.encode(value)
+ : this.queryMapEncoder.encode(value);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what can I do here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pilak: There are a few things you can do here:
-
Review the code: Look at the changes made in this pull request and provide feedback. Are there any potential issues or improvements that could be made? Do you understand the purpose of the changes?
-
Test the changes: If possible, test the new functionality to ensure it works as expected. This could involve writing unit tests or manually testing the feature.
-
Understand the context: Try to understand why these changes were made. What problem is this solving? How does it fit into the larger project?
-
Ask questions: If anything is unclear, ask for clarification. This could be about the code itself, the reasoning behind it, or how it's supposed to work.
-
Approve or request changes: Based on your review, you can approve the changes if everything looks good, or request further changes if necessary.
@velo do I have to resolve rabbitai reviews? |
not really. I'm thinking about removing it, as it's not that useful |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Status
Actionable comments generated: 2
Files selected for processing (1)
- core/src/test/java/feign/FeignTest.java (3 hunks)
Additional comments (Suppressed): 2
core/src/test/java/feign/FeignTest.java (2)
940-961: This new test case
queryMap_with_child_pojo_altered_by_getter_while_using_overriding_encoder()
appears to be testing the functionality of using an overriding encoder (FieldQueryMapEncoder
) with thequeryMapPropertyInheritenceWithBeanMapEncoder
method. The test case looks well-written and covers the necessary assertions. Good job on adding this test case.1236-1245: The
TestInterface
interface has been updated with a new methodqueryMapPropertyInheritenceWithBeanMapEncoder
. This method uses the@QueryMap
annotation with themapEncoder
attribute set toMapEncoder.BEAN
. Ensure that all calls to this method throughout the codebase have been updated to match the new signature.
import com.google.gson.Gson; | ||
import com.google.gson.reflect.TypeToken; | ||
import feign.Feign.ResponseMappingDecoder; | ||
import feign.QueryMap.MapEncoder; | ||
import feign.Request.HttpMethod; | ||
import feign.Target.HardCodedTarget; | ||
import feign.codec.DecodeException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statement for feign.QueryMap.MapEncoder
is not properly formatted. It should be aligned with the other import statements.
- import feign.QueryMap.MapEncoder;
+ import feign.QueryMap.MapEncoder;
childPojo.setChildPrivateProperty("first"); | ||
childPojo.setParentProtectedProperty("second"); | ||
childPojo.setParentPublicProperty("third"); | ||
childPojo.setParentPrivatePropertyAlteredByGetter("fourth"); | ||
|
||
server.enqueue(new MockResponse()); | ||
api.queryMapPropertyInheritence(childPojo); | ||
assertThat(server.takeRequest()) | ||
.hasQueryParams( | ||
"parentPublicProperty=third", | ||
"parentProtectedProperty=second", | ||
"childPrivateProperty=first"); | ||
"childPrivateProperty=first", | ||
"parentPrivatePropertyAlteredByGetter=fourth"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test case seems to be testing the query parameters generated when a ChildPojo
object is passed to the queryMapPropertyInheritence
method. The expected query parameters are correctly listed in the assertion. However, it would be beneficial to add some comments explaining what this test case is specifically testing for future reference.
yeah awesome but a tiny bit intrusive 😄 |
* use `mapEncoder` attribute at method level for what encoder to use * still use builder `QueryMapEncoder` if no attribute specified Co-authored-by: Pierre Lakreb <pierre.lakreb@smile.fr> Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
* use `mapEncoder` attribute at method level for what encoder to use * still use builder `QueryMapEncoder` if no attribute specified Co-authored-by: Pierre Lakreb <pierre.lakreb@smile.fr> Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
mapEncoder
attribute at method level for what encoder to useQueryMapEncoder
if no attribute specifiedHello,
Working on a project where we are using FeignBuilder in a separate library that is used like a client factory. When using some particular DTO request object, with
@QueryMap
annotation, we want to pass through the POJO getters. Unfortunately, we have to change the Builder instance ofQueryMapEncoder
fromFieldQueryMapEncoder
toBeanQueryMapEncoder
to do so, and the consequence is that this implementation will be used in every client that will be built by this factory.Also we are wondering why the choice of this encoder implementation is not closer to the annocation itself.
Here's a PR that makes possible to add the choice of the
QueryMapEncoder
implementation in a@QueryMap
annotation attribute.Doing so it is possible to change a QueryMapEncoder only of a specific method in the same Client
Summary by CodeRabbit
Release Notes:
BEAN
,FIELD
, andDEFAULT
encoding strategies.BaseBuilder
,Contract
,MethodMetadata
, andRequestTemplateFactoryResolver
classes to support the new query map encoding feature.FeignTest
to verify the functionality of the new query map encoding feature and its impact on child POJOs altered by getters.Please note that these changes may require updates to your existing code if you are directly using any of the modified classes or methods.