Tyler Murry
Tyler Murry

Reputation: 2815

Best Practice/Pattern for Transforming Java Objects

Let's say I have an application that is responsible for taking a vendor message and converting into a canonical message. For example:

public class MessageA extends VendorMessage { ... }
public class MessageB extends VendorMessage { ... }

public class MessageX extends CanonicalMessage { ... }
public class MessageY extends CanonicalMessage { ... }

Where MessageA maps to MessageX and MessageB maps to MessageY.

My approach is that I have one transformer class per message type to handle this conversion. In this example, I would have the following transformers:

public class MessageXTransfomer()
{
    public MessageX transform(MessageA message) {...}
}

public class MessageYTransfomer()
{
    public MessageY transform(MessageB message) {...}
}

My questions is really with the way I would ultimately invoke the transformers.

Since my process takes some VendorMessage as an input, I need to interrogate the type so I know which specific transformer to direct it to. For example, one approach might look like this:

public class TransfomerService
{
    MessageXTransformer messageXTransformer = new MessageXTransformer();
    MessageYTransformer messageYTransformer = new MessageYTransformer();

    public CanonicalMessage transform(VendorMessage message)
    {
        if (message instanceOf MessageA)
        {
            return messageXTransformer.transform((MessageA) message);
        }
        else if (message instanceOf MessageB)
        {
            return messageYTransformer.transform((MessageB) message);
        }
    }
}

I'm not sure why, but I this approach just feels strange - as if I'm doing something wrong. Is there a best practice for this kind of problem that I should be using?

Note: I'm looking for the best approach without using any transformation frameworks, etc. Ideally, the pattern would be achievable using just basic Java.

Upvotes: 3

Views: 5649

Answers (2)

Vadim Kirilchuk
Vadim Kirilchuk

Reputation: 3542

I like the answer of @javaguy however it is not complete. Of course it will be nice if you could use the specific transformer like in his later example, but if you can't you have to stick with TransformerFacade and kind of a StrategyPattern:

public class TransformerFacade {

    private Map<Class, VendorMessageToCanonicalMessageTransformer> transformers = new HashMap<>();
    { 
        // this is like strategies, the key may be class, class name, enum value, whatever
        transformers.put(MessageA.class, new MessageXTransformer());
        transformers.put(MessageB.class, new MessageYTransformer());
    }

    public CanonicalMessage transform(VendorMessage message) {
        return transformers.get(message.getClass()).transform(message);
    }
}

Upvotes: 5

fps
fps

Reputation: 34460

I would simply let every concrete VendorMessage return its corresponding CanonicalMessage by implementing an interface:

public interface Mapper<T> {

    T map();
}

Then, MessageA should implement this interface:

public MessageA implements Mapper<MessageX> {

    @Override
    public MessageX map() {
        MessageX message = ...;
        // fill message
        return message;
    }
}

If you don't want to do the mapping in the VendorMessage class, then a strategy as suggested by Vadim Kirilchuk in his answer would do the trick.

Upvotes: 2

Related Questions