final fields should be ignored(or be supported) when being enrich in feign.BaseBuilder
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.8k
- Forks
- 1.9k
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 41
Description
Background
We have a class that extends feign.Feign.Builder like:
public class MyBuilder extends Feign.Builder {
private static final Logger logger = LoggerFactory.getLogger(MyBuilder.class);
@Override
public <T> T target(Target<T> target) {
// custom wrapper here ...
return myWrap(super.target(target));
}
}
It works on feign-core 11.8, but when we recently upgraded it to 11.10 it failed at service startup as:
Caused by: java.lang.IllegalAccessException:
Can not set static final org.slf4j.Logger field xxx.MyBuilder.logger to org.apache.logging.slf4j.Log4jLogger
After checking the code I have found there are some changes in feign.Feign.Builder by this PR:
It will get almost all fields by getFieldsToEnrich() for enrich, then set them back to the object by Java reflection.
And in my case, the Logger logger is with final modifier so it will fail when executing field.set(thisB, enriched).
My workaround is just remove final modifier for the logger, and I think we can enhance the enrich process by either support or ignore final fields.
Proposal(ignore final fields)
List<Field> getFieldsToEnrich() {
return Util.allFields(getClass())
.stream()
// exclude anything generated by compiler
.filter(field -> !field.isSynthetic())
// and capabilities itself
.filter(field -> !Objects.equals(field.getName(), "capabilities"))
// and thisB helper field
.filter(field -> !Objects.equals(field.getName(), "thisB"))
// skip primitive types
.filter(field -> !field.getType().isPrimitive())
// skip enumerations
.filter(field -> !field.getType().isEnum())
// skip final fields
.filter(field -> !Modifier.isFinal(field.getModifiers()))
.collect(Collectors.toList());
}
Alternative proposal(support final field) , it is weird, not recommended
protected B enrich() throws Exception{
if (capabilities.isEmpty()) {
return thisB;
}
getFieldsToEnrich().forEach(field -> {
field.setAccessible(true);
if(Modifier.isFinal(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
......
}
......
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with feign.Feign.Builder, especially getFieldsToEnrich() and enrich(), and review the field handling introduced by PR 1626. Reproduce the failure with a subclass containing a static final logger, then determine whether final fields should be ignored or supported. Done means enrichment no longer fails on the final logger case and the chosen behavior is covered by an appropriate test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100