generic quickfix.Group, and writes them to the output target.
Java
import java.util.Iterator;
import quickfix.DataDictionary;
import quickfix.Field;
import quickfix.FieldMap;
import quickfix.FieldNotFound;
import quickfix.Group;
import quickfix.StringField;
public class DynamicFixPassThrough {
/**
* Recursively copies all top-level fields and repeating groups from input to output
* without relying on generated class types or hardcoded tag constants.
*/
public static void copyAllFieldsAndGroups(FieldMap input, FieldMap output, DataDictionary dictionary, String msgType) {
// 1. Copy all direct top-level fields of this map/group
Iterator<Field<?>> iterator = input.iterator();
while (iterator.hasNext()) {
Field<?> field = iterator.next();
int tag = field.getTag();
// Check if this tag represents a repeating group count tag
if (dictionary.isGroup(msgType, tag)) {
// Handle as repeating group (Step 2)
copyGroupDynamically(input, output, tag, dictionary, msgType);
} else {
// Standard non-group field copy
output.setField(new StringField(tag, field.getObject().toString()));
}
}
}
private static void copyGroupDynamically(FieldMap input, FieldMap output, int groupCountTag, DataDictionary dictionary, String msgType) {
try {
int groupCount = input.getInt(groupCountTag);
if (groupCount <= 0) {
return;
}
// Look up the group delimiter (first tag) from DataDictionary
DataDictionary.GroupInfo groupInfo = dictionary.getGroup(msgType, groupCountTag);
if (groupInfo == null) {
return; // Tag is registered as a group but group definition is missing
}
int delimiterTag = groupInfo.getDelimiterField();
// Iterate over all group instances
for (int i = 1; i <= groupCount; i++) {
// Instantiate generic Group with (counterTag, delimiterTag)
Group inputGroup = new Group(groupCountTag, delimiterTag);
input.getGroup(i, inputGroup);
Group outputGroup = new Group(groupCountTag, delimiterTag);
// RECURSION: Recursively copy fields & nested sub-groups within this group entry
copyAllFieldsAndGroups(inputGroup, outputGroup, groupInfo.getDataDictionary(), msgType);
// Add populated group instance to target map
output.addGroup(outputGroup);
}
} catch (FieldNotFound e) {
// Group count field exists, but group entries couldn't be extracted
}
}
}
How to Use It in Your Code
To execute this, retrieve the active DataDictionary from your QuickFIX/J Session/Application context:
Java
import quickfix.DataDictionary;
import quickfix.DataDictionaryProvider;
import quickfix.fix50.ExecutionReport;
public void processExecutionReport(ExecutionReport inputMsg, ExecutionReport outputMsg, DataDictionaryProvider dictProvider) {
// 1. Get the DataDictionary for FIX 5.0 (or your active session dictionary)
DataDictionary dictionary = dictProvider.getSessionDataDictionary("FIX.5.0");
// Or from Message: dictionary = dictProvider.getAppDataDictionary(inputMsg.getHeader().getString(8));
String msgType = "8"; // ExecutionReport
// 2. Run generic dynamic copy for all fields and repeating groups
DynamicFixPassThrough.copyAllFieldsAndGroups(inputMsg, outputMsg, dictionary, msgType);
}
What if a Group Tag is NOT in the Dictionary?
If you receive custom repeating groups that are completely unknown to QuickFIX/J’s DataDictionary (meaning dictionary.isGroup(msgType, tag) returns false), QuickFIX/J will not parse those fields into nested groups when the raw FIX string is first parsed into the Message object.
Instead, QuickFIX/J parses unknown repeating group fields into the root Message flat list as standard top-level fields. In that scenario, standard top-level StringField copying (Option 1 from the first response) will automatically pass them along raw without needing special group logic!