nkuprins commented on issue #198:
URL: https://github.com/apache/fesod/issues/198#issuecomment-5172105808
Hi @psxjoy, I have been thinking about this for the last week and have put
together a concrete design for it. Please, read it carefully or pin someone who
can read it :)
# Proposal: `@DictFormat` for code-label mapping
This issue is labelled `planning` and has no design written down yet, so
here is a concrete proposal to react to. I would rather agree on the shape here
than open a PR that guesses it.
## TL;DR
- **Problem**: a field stores a code (`1`), the sheet should show a label
(`Success`). Today that needs a hand-written `Converter` class per dictionary.
- **Proposal**: an annotation - `@DictFormat({"1=Success", "0=Failure"})` -
plus an enum-backed form for dictionaries that already exist in the domain
model.
- **Scope**: read and write, `String` / `Integer` / `Long` / `Short` /
`Byte` / `Boolean` / `BigInteger`; an `unmapped()` policy for partial
dictionaries.
## Proposed API
```java
public @interface DictFormat {
String[] value() default {}; // "code=label"
entries
Class<? extends Dict> type() default Dict.None.class; // or an enum
implementing Dict
UnmappedEnum unmapped() default UnmappedEnum.THROW; // THROW | NULL
| PASS_THROUGH
}
```
**Inline form**, for a mapping used in one place:
```java
@ExcelProperty("Status")
@DictFormat({"1=Success", "0=Failure"})
private Integer status;
```
**Enum-backed form**, for a dictionary that already exists:
```java
public enum Status implements Dict {
SUCCESS("1", "Success"),
FAILURE("0", "Failure");
// code() and label()
}
@ExcelProperty("Status")
@DictFormat(type = Status.class)
private Integer status;
```
`Dict` would be a two-method interface (`code()`, `label()`) that users
implement.
## Proposed behaviour
**Field types.** Codes would be written as strings in the annotation and
converted to the field type, by reusing the registered `<Type>StringConverter`
rather than any new logic.
I would propose an allowlist rather than "any type with a registered
converter", because the types left out fail *silently* rather than loudly.
**Partial dictionaries.** The annotation replaces the converter body, so it
has to decide what happens to a value the dictionary does not cover. I would
make that an explicit choice rather than pick one behaviour for everybody:
| Policy | Write | Read |
| --- | --- | --- |
| `THROW` (proposed default) | fail, naming the value | fail, naming the
label |
| `NULL` | empty cell | `null` field |
| `PASS_THROUGH` | value unchanged | cell text unchanged |
**Existing converters.** `@DictFormat` would only install a converter on a
field that does not already declare one, so an explicit
`@ExcelProperty(converter = ...)` keeps winning.
**Validation.** What would be rejected:
- **Malformed configuration** - an entry that is not `"code=label"`, or an
annotation that gives both the inline entries and an enum `type`, or neither of
them.
- **Ambiguity** - the same code or the same label used twice, including two
codes that become one value after conversion (`"1"` and `"01"` on an `Integer`
field).
- **A code the field type cannot hold** - `"abc"` on an `Integer` field, but
also `"1.9"` or a value past `Integer.MAX_VALUE`, which the numeric converters
would otherwise truncate or wrap instead of failing.
- **An empty label** - `{"1=", "0=Failure"}`, where code `1` has nothing
after the `=`. Writing a `1` would leave the cell empty, and an empty cell
comes back as `null` instead of `1`, so the value would be lost on the way back.
## Questions
1. **`"code=label"` strings, or a nested `@DictEntry(code = ..., label =
...)`?** This is the one I would most like decided before writing anything.
_The examples above use the string form throughout, but only because a proposal
needs one syntax to show_ - either would work:
```java
@DictFormat({"1=Success", "0=Failure"})
@DictFormat({
@DictEntry(code = "1", label = "Success"),
@DictEntry(code = "0", label = "Failure")
})
```
Strings are shorter and read like the mapping they describe, but the
compiler cannot see inside them - `"1:Success"` compiles and fails only when
the model is built. Separate attributes make a missing code or label a compile
error, and leave room for anything per-entry we might want later.
2. **Name/Place** `@DictFormat` is chosen to sit beside `@NumberFormat` /
`@DateTimeFormat` in `annotation/format`. Open to alternatives.
Did I miss something? Happy to adjust any of the above.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]