ISO Message Packing
ISO-8583 is a binary interchange standard for financial messages. Unlike JSON or XML, where the structure is self-describing, an ISO-8583 message is a compact byte stream. To read it you need the spec — and to implement the spec you need the packager layer.
The wire format problem
A financial authorisation request on the wire might look like this:
02 00 ← MTI: 0200 (BCD-packed in 2 bytes)
7A 34 00 ... ← 8-byte bitmap (bits 2,4,7,11,41,42 set)
37 01 23 45 67 ← field 2: PAN, LL prefix 0x37=19 digits, BCD
00 00 00 ← field 3: processing code, BCD
00 00 00 10 00 ← field 4: amount, BCD
...
The same message in an ASCII variant looks completely different:
0200 ← MTI: 4 ASCII digits
7A3400... ← 16 hex-ASCII chars for 8-byte bitmap
1901234567890... ← field 2: "19" (2 ASCII length digits) + 19 ASCII digits
Without knowing the packager spec, neither stream is parseable. The packager layer is the bridge between the Java object model and the raw bytes.
Class hierarchy at a glance
ISOComponent (abstract) ← Composite Pattern base
├── ISOField ← Leaf: String value
├── ISOBinaryField ← Leaf: byte[] value
├── ISOBitMap ← Leaf: BitSet (stored at field -1)
└── ISOMsg ← Composite: TreeMap of ISOComponents
ISOPackager (interface) ← packs/unpacks a whole ISOMsg
└── ISOBasePackager (abstract) ← drives the fld[] array + bitmap logic
└── GenericPackager ← XML-configured concrete packager
ISOFieldPackager (abstract) ← packs/unpacks one field
├── ISOStringFieldPackager ← strategy-based: Padder+Interpreter+Prefixer
│ ├── IFA_NUMERIC / IFA_CHAR / IFA_LLCHAR / IFA_LLLCHAR …
│ ├── IFB_NUMERIC / IFB_BINARY / IFB_LLNUM / IFB_LLLCHAR …
│ └── IF_CHAR
├── ISOBitMapPackager (abstract) ← special base for bitmap fields
│ ├── IFA_BITMAP ← hex-ASCII bitmap
│ └── IFB_BITMAP ← raw binary bitmap
└── ISOMsgFieldPackager ← wraps an inner ISOMsg (sub-messages)
The round-trip
┌───────────────────────────────────────────────┐
│ ISOMsg │
│ field 0: ISOField("0200") │
│ field -1: ISOBitMap({2,3,4,...}) │
│ field 2: ISOField("4111111111111111") │
│ field 3: ISOField("000000") │
│ field 4: ISOField("000000001000") │
└───────────────────────────────────────────────┘
│ ISOPackager.pack()
▼
byte[] (network frame)
│ ISOPackager.unpack()
▼
┌───────────────────────────────────────────────┐
│ ISOMsg │
└───────────────────────────────────────────────┘
The following sections walk through each layer in detail:
- ISOComponent: Composite Pattern — how
ISOMsg,ISOField,ISOBinaryField, andISOBitMapfit together - Field Packagers — the
IF*naming system,ISOStringFieldPackager, and the Padder/Interpreter/Prefixer strategies - Bitmaps — how the bitmap is built, packed, and unpacked
- GenericPackager — XML-driven packager configuration
- ISOUtil — byte manipulation helpers used throughout the codebase