Schema introspection
Since 1.9.0 the field layout of a @Record class can be queried at runtime through the
FixedFormatIntrospector interface, implemented by FixedFormatManagerImpl. This serves
tooling built on top of the annotated schema — documentation generators, UI form builders,
format negotiation (detecting offset/length drift between record class versions), and layout
assertions in tests — without re-implementing annotation scanning.
FixedFormatIntrospector introspector = new FixedFormatManagerImpl();
for (FieldInfo field : introspector.introspect(CustomerRecord.class)) {
System.out.printf("%-15s offset=%2d length=%2d type=%s%n",
field.getPropertyName(), field.getOffset(), field.getLength(),
field.getDataType().getSimpleName());
}
customerId offset= 1 length=10 type=String
customerName offset=11 length=20 type=String
FixedFormatIntrospector is a separate interface rather than an addition to
FixedFormatManager, so existing third-party manager implementations stay source and binary
compatible; callers that only need schema access can depend on the narrow contract.
FieldInfo
introspect() returns one immutable FieldInfo per effective @Field, ordered by offset.
A getter carrying @Fields contributes one entry per inner @Field.
| Accessor | Meaning |
|---|---|
getPropertyName() |
Bean-style property name (getCustomerId() → customerId); for Java records, the component name as-is |
getOffset() / getLength() |
1-based offset; length -1 = rest-of-line |
getDataType() |
Declared Java type (the collection/array type for repeating fields) |
getEffectiveAlignment() |
Resolved LEFT/RIGHT — record-level defaults already applied, never INHERIT |
getPaddingChar() |
Padding character |
getNullChar() / getNullValue() |
Null sentinels (UNSET_NULL_CHAR / "" when not configured) |
getFormatterClass() |
Configured formatter (ByTypeFormatter unless overridden) |
getRepeatCount() |
count attribute; 1 for non-repeating fields |
isNestedRecord() |
true when the field type is itself a @Record class |
Validation preflight
introspect() triggers the same one-time metadata build and annotation validation as
load()/export(), so it doubles as a startup preflight check: an invalid configuration
(bad date pattern, enum too wide, misconfigured null sentinel, …) throws
FixedFormatException at introspection time. For build-time validation, see
Compile-time validation.
Performance: the underlying scan and validation run once per class (the same cached
metadata used by load()/export()); each introspect() call performs only an
O(number of fields) mapping with no I/O and no reflection beyond the cached metadata.