0

I’m building a FIX message which in typical case would be built something like this:

Message message =  new News();
message.setField(new SenderCompID("me"));
message.setField(new TargetCompID("you"));
...
message.setField(new BookSubType("whatever"));

Input is a hash-map:

HashMap<String, String> hmap = new HashMap<String, String>();
hmap.put("SenderCompID", "me");
hmap.put("TargetCompID", "you");
…
hmap.put("BookSubType", "whatever");

One way to construct the message from this input would be:

String senderCompID = hmap.get("SenderCompID");
if (senderCompID != null && !senderCompID.equals("")) {
    message.setField(new SenderCompID(senderCompID));
}
…

And so on for every field. But there are too many fields, I will end up spending days writing this. It would be handy if I could dynamically create objects, using hmap keys. My best attempt so far is this:

for (Map.Entry<String, String> entry : hmap.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();

    Class c = Class.forName(key);
    Constructor con = c.getConstructor(SenderCompID.getClass());
    Object xyz = con.newInstance(value);

    if (xyz instanceof SenderCompID) {
        message.setField((SenderCompID) xyz);
    } else if ( xyz instanceof TargetCompID ) {
        message.setField((TargetCompID) xyz);
    } else if …
}

Is there a way to get rid of “if else” statements? The class to which I’m casting to is stored in a String (key), can’t I somehow cast it using the key from the map?

user52028778
  • 27,164
  • 3
  • 36
  • 42
  • I suspect there should be a base type that is parent of all those `xxxxID` types that you can use for cast. – SomeDude Jan 09 '18 at 14:30
  • 2
    What is the signature of the `Message.setField` method? It is quite probable that `XyzID` have some base type you can cast to - and that `setField` accepts this type as argument. If nothing else helps, you can find and invoke the appropriate `setField` method via reflection. – lexicore Jan 09 '18 at 14:37
  • why not keep a reference to the Class as you create the objects instead of using a String. Then you could just call Class.cast(object) – John Kane Jan 09 '18 at 14:38
  • @lexicore @svasca setField accepts StringField, but there are also at least DoubleFields and IntFields. `StringField xyz = (StringField) con.newInstance("me");message.setField((StringField) xyz);` works ok, but how do I figure out what kind of Field an input is? – user52028778 Jan 09 '18 at 15:19
  • @JohnKane Do you mean the classes when calling `new SenderCompID(senderCompID)`? SenderCompID is coming from the input, I'm trying to make it variable. – user52028778 Jan 09 '18 at 15:23

1 Answers1

0

You can use a Map of Class as keys, then use the Class<T>::cast feature to get rid of the if-else clauses:

final Map<Class<? extends MyBaseClass>, String> map = new HashMap<Class<? extends MyBaseClass>, String>();

map.put(SenderCompID.class, "me"); // SenderCompID, TargetCompID are all subclasses of MyBaseClass

// ....

for (Map.Entry<Class<? extends MyBaseClass>, String> entry : hmap.entrySet()) {
    Class<? extends MyBaseClass> klass = entry.getKey();

    // your operations ...

    message.setField(klass.cast(xyz));
}
payloc91
  • 3,724
  • 1
  • 17
  • 45