Skip to content

Commit 19622df

Browse files
authored
docs: update specifications
1 parent 6359a5c commit 19622df

1 file changed

Lines changed: 79 additions & 14 deletions

File tree

SPECIFICATIONS.md

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,14 @@ Each Java type maps to a default column renderer and configuration:
2727
| `LocalDate` | `LocalDateRenderer` | Start | Chronological |
2828
| `LocalDateTime` | `LocalDateTimeRenderer` | Start | Chronological |
2929
| `LocalTime` | `TextRenderer` (formatted) | Start | Chronological |
30-
| `Enum<?>` | `TextRenderer` (name) | Start | Alphabetical |
30+
| `Enum<?>` | `TextRenderer` (`toString()`) | Start | Alphabetical |
3131

3232
Custom type mappings can be registered globally or per-grid instance.
3333

34+
**Boolean rendering:** `Boolean` columns render as the string literals `"true"` or `"false"` by default. Any other representation ("Yes"/"No", "On"/"Off", localised strings, etc.) requires a custom formatter — typically one that delegates to an application i18n provider.
35+
36+
**Enum rendering:** Enum columns render using `Enum.toString()`, not `Enum.name()`. Per the Java documentation for `Enum.name()`: *"Most programmers should use the toString method in preference to this one, as the toString method may return a more user-friendly name."* Enums that need human-readable labels should override `toString()` accordingly.
37+
3438
### 2.3 Sorting
3539

3640
All columns backed by `Comparable` property types are sortable by default. Multi-column sorting is supported.
@@ -139,22 +143,83 @@ easyGrid.getColumn("firstName")
139143

140144
See [FEATURE_ROW_ACTIONS.md](FEATURE_ROW_ACTIONS.md).
141145

142-
### 3.5 Global Type Configuration
146+
### 3.5 Type Configuration Tree
147+
148+
Column display configuration is resolved through a three-level tree, from most to least specific:
149+
150+
| Level | API | Scope |
151+
|---|---|---|
152+
| **Column** | `EasyColumn` setters | One specific column |
153+
| **Instance** | `EasyGrid.forType(Class)` | All columns of that type in one grid |
154+
| **Global** | `GlobalEasyGridConfiguration.forType(Class)` | All grids in the application |
155+
156+
Within each level the class hierarchy is walked before the tree falls through to the next level (scope-first). The full resolution order for a `Foo extends Entity` column is:
157+
158+
```
159+
Column·Foo
160+
→ Instance·Foo → Instance·Entity → Instance·Object
161+
→ Global·Foo → Global·Entity → Global·Object
162+
→ Built-in default
163+
```
164+
165+
The first non-`null` value found wins. See [CONFIGURATION_RESOLUTION.md](CONFIGURATION_RESOLUTION.md) for the rationale behind scope-first ordering.
166+
167+
**Column level**`EasyGrid.addColumn(…)` returns an `EasyColumn` whose setters write into an isolated configuration node at the top of the chain for that column only:
168+
169+
```java
170+
easyGrid.addColumn("active").setNullRepresentation("");
171+
easyGrid.addColumn("salary").setTextAlign(ColumnTextAlign.END);
172+
```
173+
174+
**Instance level**`EasyGrid.forType(Class)` returns the instance-level `ColumnConfiguration` for a type. Changes apply to every column of that type on this grid:
175+
176+
```java
177+
easyGrid.forType(BigDecimal.class)
178+
.setRendererFactory(NumberRenderers.of("%,.2f", Locale.US));
179+
```
180+
181+
**Global level**`GlobalEasyGridConfiguration.forType(Class)` returns the application-wide `ColumnConfiguration`. Call `GlobalEasyGridConfiguration.freeze()` after startup to prevent further modifications:
182+
183+
```java
184+
GlobalEasyGridConfiguration.forType(LocalDate.class)
185+
.setRendererFactory(LocalDateRenderers.of("dd/MM/yyyy"));
186+
GlobalEasyGridConfiguration.freeze();
187+
```
188+
189+
#### Null Representation
143190

144-
Register custom column configurations that apply to all `EasyGrid` instances:
191+
The `nullRepresentation` property controls what is displayed when a column value is `null`. The built-in global default registers `""` (empty string) on `Object.class`, so every column starts with an empty cell for `null` values. Override it at any level:
145192

146193
```java
147-
// Register a global formatter for a custom type
148-
EasyGrid.registerTypeConfig(Money.class, config -> {
149-
config.setFormatter(money -> money.getCurrency() + " " + money.getAmount());
150-
});
151-
152-
// Register a global renderer for nested types
153-
EasyGrid.registerTypeConfig(Address.class, config -> {
154-
config.setFormatter(address ->
155-
address.getStreet() + ", " + address.getCity()
156-
);
157-
});
194+
// All columns in this grid show "–" for null
195+
easyGrid.forType(Object.class).setNullRepresentation("");
196+
197+
// Only the "email" column shows "(none)" for null
198+
easyGrid.addColumn("email").setNullRepresentation("(none)");
199+
```
200+
201+
Formatters that receive a `ColumnConfiguration` parameter can call `getNullRepresentation()` to produce consistent output.
202+
203+
#### Type Hierarchy Support
204+
205+
Inside each scope level, `EasyGridConfigurationClassMap` walks the Java class hierarchy. When a configuration is requested for `Foo` and none exists, it is created with `Foo`'s superclass configuration as its parent, continuing up to `Object`. Primitive types are mapped to their boxed counterparts before hierarchy walking (`int``Integer`, `boolean``Boolean`, etc.).
206+
207+
A global `Number.class` renderer factory is therefore automatically inherited by `Integer`, `Long`, `BigDecimal`, and every other `Number` subtype unless a more specific configuration overrides it.
208+
209+
#### Renderer Utility Classes
210+
211+
Three `@UtilityClass` types in `com.flowingcode.vaadin.addons.easygrid.renderers` produce `RendererFactory` instances for common value types:
212+
213+
- **`LocalDateRenderers`** — wraps `LocalDateRenderer`; overloads accept a format pattern, locale, null representation, or a `DateTimeFormatter` supplier.
214+
- **`LocalDateTimeRenderers`** — wraps `LocalDateTimeRenderer`; same overloads as `LocalDateRenderers`.
215+
- **`NumberRenderers`** — wraps `NumberRenderer`; overloads accept a `NumberFormat`, a `Locale`, or a `Formatter` pattern string with optional locale and null representation.
216+
217+
```java
218+
GlobalEasyGridConfiguration.forType(LocalDate.class)
219+
.setRendererFactory(LocalDateRenderers.of("dd/MM/yyyy", Locale.UK));
220+
221+
GlobalEasyGridConfiguration.forType(Number.class)
222+
.setRendererFactory(NumberRenderers.of(NumberFormat.getInstance()));
158223
```
159224

160225
## 4. Default Header Generation

0 commit comments

Comments
 (0)