Search before asking
Fesod version
main (2.1.0-incubating). Not tied to a recent change — the explicit-key case below reproduces on released versions too.
JDK version
17 (Temurin); not JDK-specific.
Operating system
Any
Steps To Reproduce
public static class Bean {
@ExcelProperty("flag")
private String flag;
// getters / setters
}
public static class UpperCaseConverter implements Converter<String> {
@Override public Class<?> supportJavaTypeKey() { return String.class; }
@Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; }
@Override public String convertToJavaData(
ReadCellData<?> cellData, ExcelContentProperty p, GlobalConfiguration g) {
return cellData.getStringValue().toUpperCase();
}
}
// file under test: header "flag", one data row with the value "abc"
FesodSheet.write(file, Bean.class).sheet().doWrite(Collections.singletonList(new Bean("abc")));
List<Bean> rows = FesodSheet.read(file, Bean.class, listener)
.registerConverter(new UpperCaseConverter())
.sheet()
.doReadSync();
// rows.get(0).getFlag() is null
Current Behavior
The converter is invoked with the header cell ("flag") instead of the data cell ("abc"): convertToJavaData returns "FLAG", the framework then compares "FLAG" with the @ExcelProperty("flag") name, finds no matching column, and leaves the field null. No exception is raised, so the failure is silent.
The same path also fills AnalysisEventListener.invokeHeadMap(...), so the header map handed to listeners goes through user converters as well.
Using @ExcelProperty(index = 0) works, because matching then does not depend on the header text.
Expected Behavior
When the framework converts the head row to strings for name matching, header cells should be resolved against the built-in converters — user-registered converters are meant for data cells. invokeHeadMap should likewise receive the raw header text.
Note that in the failing case the converter is never invoked for the data cell either, so even a user who wants header conversion loses data conversion entirely.
Anything else?
Root cause: ConverterUtils.convertToStringMap resolves ConverterKeyBuild.buildKey(String.class, cellData.getType()) in the holder's converter map, which also contains user registrations. It is called from DefaultAnalysisEventProcessor.buildHead (header to field matching) and from AnalysisEventListener.invokeHead.
Found while reviewing #1086 (read-side wildcard converter fix). That PR does not introduce this — an explicit (String, STRING) registration already reproduces it on main. It does widen the set of affected registrations, since a wildcard Converter<String> gets expanded to (String, STRING) and would therefore be picked up by the header path too.
Proposed fix: resolve the header path against the built-in read converters (e.g. DefaultConverterLoader.copyDefaultReadConverter()) rather than the user-extended map. One decision point for the maintainers: whether invokeHeadMap should keep seeing user-converted text (a niche behaviour someone might rely on) or always see the raw header.
Happy to prepare the PR if the direction looks right — unless it is preferred to handle this within #1086.
Are you willing to submit a PR?
Search before asking
Fesod version
main (2.1.0-incubating). Not tied to a recent change — the explicit-key case below reproduces on released versions too.
JDK version
17 (Temurin); not JDK-specific.
Operating system
Any
Steps To Reproduce
Current Behavior
The converter is invoked with the header cell (
"flag") instead of the data cell ("abc"):convertToJavaDatareturns"FLAG", the framework then compares"FLAG"with the@ExcelProperty("flag")name, finds no matching column, and leaves the fieldnull. No exception is raised, so the failure is silent.The same path also fills
AnalysisEventListener.invokeHeadMap(...), so the header map handed to listeners goes through user converters as well.Using
@ExcelProperty(index = 0)works, because matching then does not depend on the header text.Expected Behavior
When the framework converts the head row to strings for name matching, header cells should be resolved against the built-in converters — user-registered converters are meant for data cells.
invokeHeadMapshould likewise receive the raw header text.Note that in the failing case the converter is never invoked for the data cell either, so even a user who wants header conversion loses data conversion entirely.
Anything else?
Root cause:
ConverterUtils.convertToStringMapresolvesConverterKeyBuild.buildKey(String.class, cellData.getType())in the holder's converter map, which also contains user registrations. It is called fromDefaultAnalysisEventProcessor.buildHead(header to field matching) and fromAnalysisEventListener.invokeHead.Found while reviewing #1086 (read-side wildcard converter fix). That PR does not introduce this — an explicit
(String, STRING)registration already reproduces it onmain. It does widen the set of affected registrations, since a wildcardConverter<String>gets expanded to(String, STRING)and would therefore be picked up by the header path too.Proposed fix: resolve the header path against the built-in read converters (e.g.
DefaultConverterLoader.copyDefaultReadConverter()) rather than the user-extended map. One decision point for the maintainers: whetherinvokeHeadMapshould keep seeing user-converted text (a niche behaviour someone might rely on) or always see the raw header.Happy to prepare the PR if the direction looks right — unless it is preferred to handle this within #1086.
Are you willing to submit a PR?