Skip to content

Instantly share code, notes, and snippets.

@hitxiang
Forked from CN6033/fix2json.java
Last active March 26, 2024 04:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hitxiang/6715b1d25c26eebecd981668520f3bd1 to your computer and use it in GitHub Desktop.
Save hitxiang/6715b1d25c26eebecd981668520f3bd1 to your computer and use it in GitHub Desktop.
FIX message to JSON convertor
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import quickfix.FieldNotFound;
import quickfix.Message;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class FIX2Json {
private static final Gson gson = new Gson();
private Map<Integer, String> tagToNameMap;
public FIX2Json() {
tagToNameMap = new HashMap<>();
tagToNameMap.putAll(getTagToNameMap("quickfix.field"));
}
private static Map<Integer, String> getTagToNameMap(String packageName) {
Map<Integer, String> tagToNameMap = new HashMap<>();
try {
ClassPath classPath = ClassPath.from(ClassLoader.getSystemClassLoader());
ImmutableSet<ClassPath.ClassInfo> classes = classPath.getTopLevelClasses(packageName);
for (ClassPath.ClassInfo classInfo : classes) {
Field field;
try {
field = classInfo.load().getField("FIELD");
} catch (NoSuchFieldException e) {
continue;
}
int fieldTag = field.getInt(null);
String fieldName = classInfo.getSimpleName();
tagToNameMap.put(fieldTag, fieldName);
}
} catch (IOException | IllegalAccessException e) {
e.printStackTrace();
}
return tagToNameMap;
}
public String fix2Json(Message message) {
JsonObject jsonObject = new JsonObject();
quickfix.Message.Header header = message.getHeader();
Iterator<quickfix.Field<?>> headerIterator = header.iterator();
while (headerIterator.hasNext()) {
quickfix.Field<?> field = headerIterator.next();
String name = tagToNameMap.get(field.getTag());
if (name == null) {
name = String.valueOf(field.getTag());
}
try {
jsonObject.addProperty(name, header.getString(field.getTag()));
} catch (FieldNotFound fieldNotFound) {
// ignore, should not happen
}
}
Iterator<quickfix.Field<?>> bodyIterator = message.iterator();
while (bodyIterator.hasNext()) {
quickfix.Field<?> field = bodyIterator.next();
String name = tagToNameMap.get(field.getTag());
if (name == null) {
name = String.valueOf(field.getTag());
}
try {
jsonObject.addProperty(name, message.getString(field.getTag()));
} catch (FieldNotFound fieldNotFound) {
// ignore, should not happen
}
}
jsonObject.addProperty("RawData", message.toString());
return gson.toJson(jsonObject);
}
}
public class QuickfixjMessageJsonTransformer {
private DataDictionary dataDictionary;
public QuickfixjMessageJsonTransformer(){};
public QuickfixjMessageJsonTransformer(DataDictionary dd) {
this.dataDictionary = dd;
}
public String transform(Exchange exchange) {
// camel message
org.apache.camel.Message in = exchange.getIn();
if (dataDictionary == null) { // the following code doesn't work for FIXT
SessionID sessionID = in.getHeader(QuickfixjEndpoint.SESSION_ID_KEY, SessionID.class);
Session session = Session.lookupSession(sessionID);
dataDictionary = session.getDataDictionary();
}
if (dataDictionary == null) {
throw new IllegalStateException("No Data Dictionary. Exchange must reference an existing session");
}
String jsonStr;
try {
jsonStr = convertToJSON(dataDictionary, in.getBody(Message.class));
} catch (FieldNotFound | FieldException ex) {
throw new IllegalStateException("Cannot convert to JSON", ex);
}
return jsonStr;
}
static String convertToJSON(DataDictionary dd, quickfix.Message message) throws FieldNotFound {
ObjectMapper mapper = new ObjectMapper();
ObjectNode rootNode = mapper.createObjectNode();
convertFieldMapToJSON(dd, message.getHeader(), rootNode);
convertFieldMapToJSON(dd, message, rootNode);
convertFieldMapToJSON(dd, message.getTrailer(), rootNode);
//rootNode.put("raw", message.toString());
return rootNode.toString();
}
private static void convertFieldMapToJSON(
DataDictionary dd,
FieldMap fieldmap,
ObjectNode node
) throws FieldNotFound {
Field<?> field;
String fieldName;
int tag;
Iterator<Field<?>> fieldIterator = fieldmap.iterator();
while (fieldIterator.hasNext()) {
field = fieldIterator.next();
tag = field.getField();
fieldName = dd.getFieldName(tag);
if (!isGroupCountField(dd, field)) {
if (dd.hasFieldValue(tag)) { // enumerated values
node.put(fieldName, dd.getValueName(tag, field.getObject().toString()));
} else {
if (Number.class.isAssignableFrom(dd.getFieldType(tag).getJavaType())) {
node.put(fieldName, fieldmap.getDecimal(tag));
} else {
node.put(fieldName, fieldmap.getString(tag));
}
}
}
}
Iterator<Integer> groupsKeys = fieldmap.groupKeyIterator();
while (groupsKeys.hasNext()) {
int groupTag = groupsKeys.next();
String groupName = dd.getFieldName(groupTag);
if (isMarketDataType(node)) {
ObjectNode repeatingGroup = node.putObject(groupName);
for (Group group : fieldmap.getGroups(groupTag)) {
if (group.isSetField(MDEntryType.FIELD)) {
ObjectNode groupNode = repeatingGroup.putObject(dd.getValueName(MDEntryType.FIELD, group.getString(MDEntryType.FIELD)));
convertFieldMapToJSON(dd, group, groupNode);
} else {
convertFieldMapToJSON(dd, group, repeatingGroup);
}
}
} else {
ArrayNode repeatingGroup = node.putArray(groupName);
for (Group group : fieldmap.getGroups(groupTag)) {
ObjectNode groupNode = repeatingGroup.addObject();
convertFieldMapToJSON(dd, group, groupNode);
}
}
}
}
private static boolean isMarketDataType(ObjectNode node) {
return Objects.nonNull(node.get("MsgType")) && "\"MarketDataIncrementalRefresh\"".equals(node.get("MsgType").toString());
}
private static boolean isGroupCountField(DataDictionary dd, Field field) {
return dd.getFieldType(field.getTag()) == FieldType.NUMINGROUP;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment