Parser (FIN MT to Java)
The parser provides functionality to convert SWIFT messages FIN text into the Java message model
By doing this, you can work with SWIFT messages focusing on the data and not having to deal with low level syntax details.
The parser always performs a best effort heuristic to parse the message even if it is not well formed. All the information is read and put in a suitable object of the message model regardless of the message being SWIFT compliant.
The parser functionality has different entry point depending on the use case:
Generic processing of unknown messages
In situations where the message type is unknown, the easiest and recommended way to read and parse messages is by means
of the abstract class AbstractMT. This class provides static methods to parse an unknown message from a String
or
InputStream
.
For example consider the following SWIFT message example:
{1:F01BANKDEFMAXXX2039063581}{2:O1031609050901BANKDEFXAXXX89549829458949811609N}{4:
:20:007505327853
:23B:CRED
:32A:050902JPY3520000,
:33B:JPY3520000,
:50K:EUROXXXEI
:52A:FEBXXXM1
:53A:MHCXXXJT
:54A:FOOBICXX
:59:/13212312
RECEIVER NAME S.A
:70:FUTURES
:71A:SHA
:71F:EUR12,00
:71F:EUR2,34
-}
Assuming the message is in a String variable "fin", the following code will parse the FIN message into a message object object, where several getters are available to read message header information.
AbstractMT msg = AbstractMT.parse(fin);
String sender = msg.getSender();
String type = msg.getMessageType();
Even though the message type is unknown the returned object will be parsed into its specific MTnnn
model object. So once
the message type is known a simple cast is enough to access detail information of the text block for reading or
manipulating its content. In the example:
System.out.println(msg.getMessageType());
if (msg.isType(103)) {
MT103 mt = (MT103) msg;
// print the message reference
System.out.println("Reference: "+mt.getField20().getValue());
// read components of a specific field
Field32A f = mt.getField32A();
Calendar date = f.getComponent1AsCalendar();
Number amount = f.getComponent3AsNumber();
}
Notice MTnnn
classes provide API that is exclusively related to the fields that can be present in each message type.
Parsing an unknown message for persistence
While in the context of a parsing an unknown message, if the ultimate requirement is to read just headers information,
persist the message into a database or to process large bursts of messages, the recommended way to read and parse
messages is by means of the MtSwiftMessage class. This class also implements several ways to create the message
instance from String
, InputStream
; but only header information is read and the model is kept generic after the parse.
Assuming the message is in a String
or InputStream
variable "fin" , the following code will parse the FIN message
into a MtSwiftMessage
object, and getters are used to access message header information.
MtSwiftMessage msg = MtSwftMessage.parse(fin);
String sender = msg.getSender();
String type = msg.getMessageType();
The MtSwiftMessage
is a lightweight representation of the message where only the header and trailer blocks are parsed
and modeled, while the text block (the actual business payload) is kept in its raw unparsed format.
Specializing an unkown message
The above way of reading messages is the most efficient in terms of performance and it is useful to process large burst of messages; but it is limited for content manipulation.
However, once the message object is created and properly identified, it can be specialize to access the specific text block content, for example:
MT103 mt = new MT103(msg);
Field32A f = mt.getField32A();
Calendar date = f.getComponent1AsCalendar();
Number amount = f.getComponent3AsNumber();
Notice that specializing a generic message from an AbstractMT
requires only a cast to the specific MTnnn
, while doing
the same from an MtSwiftMessage requires a constructor.
Another important thing to know when deciding to use the AbstractMT or the MtSwiftMessage
is that parsing by an
AbstractMT
implies that the message type can be determined from the block 2 header, that's because internally the parser
will create the corresponding message type object (MTnnn
). While parsing by an MtSwiftMessage
does not impose anything
to the message content, that could be malformed or incomplete and the message object will be created anyway.
Specific processing of a known message type
When the message to parse is known, the specific model class can be used directly to parse and read the content. For example:
Where the fin parameter can be aString
or InputStream
with the message in its FIN format, and the parsing can be
called using the static parse method (as in the example) or by an MTnnn
constructor.
Once the object is created all its specific content can be read using getters for specific sequences and fields.
Parsing message with ACK
There is a frequent misunderstanding of the FIN messages format when the actual message is preceded by a system ACK, and the expected behavior of Prowide Core parser when reading such messages.
The following example is actually a service message for ACK, followed by the original MT940 sent:
{1:F21FOOLHKH0AXXX0304009999}{4:{177:1608140809}{451:0}}{1:F01FOOLHKH0AXXX0304009999}{2:O9401609160814FOOLHKH0AXXX03040027341608141609N}{4:
:20:USD940NO1
:21:123456/DEV
:25:USD234567
:28C:1/1
:60F:C160418USD672,
:61:160827C642,S1032
:86:ANDY
:61:160827D42,S1032
:86:BANK CHARGES
:62F:C160418USD1872,
:64:C160418USD1872,
-}{5:{CHK:0FEC1E4AEC53}{TNG:}}{S:{COP:S}}
If you pass the above content to the parse method, by default the parser will get the first FIN message found in the file (the ACK service message), leaving the rest of the text into the UnparsedTextList structure.
This is just fine when reading plain user to user messages, but when the message is preceded by a service message as in the example, the resulting parsed object may not be the expected one.
When dealing with this scenario it is the user responsibility to check whether the message is a service message or not, and proceed accordingly, depending on the particular use case and application needs.
If you are trying to match and process the ACK/NAK notifications you may be interested on the service message. However, if this is the way you receive the messages from the SWIFT interface and you need the actual user message following the ACK, then you have to do something else.
The following example will parse the FIN content, check for the service id, and if it is a system message it will then gather the actual MT from the unparsed content:
SwiftMessage sm = SwiftMessage.parse(fin);
if (sm.isServiceMessage()) {
sm = SwiftMessage.parse(sm.getUnparsedTexts().getAsFINString());
}
At this point the sm variable will contain the actual user to user message, regardless if it was preceded by and ACK.
For more information on the ACK/NAK structure see Processing ACK/NAK.
Direct usage of the SwiftParser
Finally, the actual parser implementation class is another option to translate a raw message in its Java model object.
Direct usage of theSwiftParser
class is discouraged but in may be useful on certain conditions where the lenient mode
of the parser must be explicitly controlled by your application.
The result of the parser is the backbone model implemented by the SwiftMessage class. So the parser will basically split the message content into the three primary elements that defines an MT message; the message itself, it's blocks, and the tag (or fields) inside each block.
Reading fields like simple tuples of name and value makes the parser very efficient, while additional content parsing can be done with the message model in a following step.
For the example, the following code can be use to gather some fields of the parsed message using the generic low level model:
String val32a = m.getBlock4().getTagValue("32A"); //get a simple value tag
String[] list71 = m.getBlock4().getTagValues("71F"); //get a repeated value tag
String
with values
"EUR12,00" and "EUR2,34".
The SwiftBlock4
object basically contains an ordered List of fields found content body of the SWIFT message and provides
several API to manipulate and get the tags individually or by sub blocks. At this API level the message body can be
think of as a text string, where instead of characters we found message fields and we can get for example all Tags
before a given one, Tags between boundaries, etc.. This API is the base foundation of the high level Sequences API.