-2
\$\begingroup\$

Similar question

  • MessageFormat: represents the various kinds of messages. (XML, JSON, custom)
  • Message: represents an abstract Java Object for any kind of message.
  • Schema: represents an abstract Java Object for any kind of message descriptor. (Contains MessageFormat.)
  • SchemaFormat: represents all kinds of schemas. (XSD, JSON Schema, XML respectively for each MessageFormat)
  • MessageParser: contains a method for parsing messages: Message parse(String, Schema).

When I implement a MessageParser, I meet the following issue: I need to accept a concrete class of Schema in the method parameter as opposed to the Schema itself as it is defined in the interface. Currently, I delegate with downcasting. Should I accept Schema and downcast inside the method? Either way, it seems I unnecessarily cast.

public class FixedLengthStringMessageParser implements MessageParser {


    @Override
    public Message parse(final String msg, 
                         final Schema schemaXML
                        ) {
        return parse(msg, (XMLSchema) schemaXML);
    }

    //TODO two methods is ugly
    private FixedLengthStringMessage parse(final String msg,
                                             final XMLSchema schema
                                            ) {

        String str = msg.getData();

        HashMap<String, Long> metrics = new HashMap<>();

        int counter = 0;
        for (Map.Entry<String, Integer> entry : schema.getMetrics().entrySet())
            metrics.put(entry.getKey(), Long.valueOf(str.substring(counter, counter += entry.getValue())));

        return new FixedLengthStringMessage(metrics);
    }
}

While I can declare the return type as FixedLengthStringMessage instead of the Message, I cannot declare the parameters in such a way, because that implementation "does not count".

\$\endgroup\$
  • \$\begingroup\$ I've reworded it! \$\endgroup\$ – Sam Aug 4 '17 at 9:31
  • \$\begingroup\$ msg.getData() seems to be a relic from when you still had the class Serialized, since String doesn't have a getData() method. Also, I haven't look at it in detail yet (I have to leave shortly), but I smell design flaw, and it might help if you also posted the code for XMLSchema to detect it. \$\endgroup\$ – Stingy Aug 4 '17 at 16:57
1
\$\begingroup\$

The implementation 'does not count' as it overloads the method and does not override it. You can use generics to specify the expected parameter type.

If you can change the MessageParser interface:

interface MessageParser<T extends Schema> {
    Message parse(String msg, T schema);
}

The implementation would be

public class FixedLengthStringMessageParser implements MessageParser<XMLSchema> {
    public FixedLengthStringMessage parse(String msg, XMLSchema schema) {
        ...
    }
}

If you cannot/do not want to change the interface, you can use an intermediate abstract class to have the forwarding method only once for all implementations

abstract class AbstractParser<T extends Schema> implements MessageParser {
    public final Message parse(String msg, Schema schema) {
        return parse0(String msg, (T) schema);
    }
    protected abstract Message parse0(String msg, T schema);
}
\$\endgroup\$
  • \$\begingroup\$ I like the idea with generics. Thank you very much, sir :) \$\endgroup\$ – Sam Aug 4 '17 at 7:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.