Skip to main content

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, and ISOBitMap fit 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