Xml deserialization - at least in case of C# (you're not referring to it directly, but your links indicate it as your language of choice) - has type recognition built in. Why not make use of that?
See https://stackoverflow.com/questions/775647/how-do-i-deserialize-xml-without-knowing-the-type-beforehand for more details.
1: Make some super class that contains every possibility of contained
types.
As demonstrated in the question I linked to above, all it takes is creating some common base class for your errorMessage
objects. Then you need to use XmlInclude
.
So the super class would only have to "contain every possibility" in the sense of knowing about all its subtypes (but not their implementation details). It's still all nice and neat in terms of OOP.
Note that if you feel that .NET serialization is too limiting, there's always more sophisticated alternatives such as SharpSerializer - better suited for polymorphic scenarios.
Again, this is not a language-agnostic suggestion, but if you used another programming language, the advice still applies: you can look for a good open-source library.
2: Make some mechanism for reading the xml first to identify what's in it.
You could also use reflection and retrieve the type in run-time (as Kirtan suggested) by the name of the root element, or some attribute of the root element.
Another option would be to create, or generate, XSD schemas for your errorMessage
items, then use these schemas to validate the incoming messages - thus establishing their "type identity".
One advantage of this admittedly a bit more troublesome solution is that if the incoming xml was somehow broken, xsd validation could tell you exactly where and why (eg. some unexpected, unrecognized element), you don't have to handle this "manually".
Then there's dynamic typing and yet another interesting approach:
https://stackoverflow.com/a/13705918/168719
A more elegant approach would be to implement some kind of Action
pattern, where, once the object was identified you could create the
proper action to take with it.
That's what takes place after you deserialize the message, doesn't it?
With regard to this, I don't think one could come up with suggestions superior to what you have already found in this thread: https://stackoverflow.com/questions/298976/is-there-a-better-alternative-than-this-to-switch-on-type
I hope this gives you some inspiration. If not, the principle I go by is: when it's awfully hard to solve a problem, most likely the problem itself is badly posed from the very beginning. So if you are stuck, maybe it's time to step back and redesign. I don't know broader context, so I have no way of knowing how possible it is in your case.
As a best practice, try and make your DTOs as concise as possible. Only return what you need to return. Only use what you need to use. If that means a few extra DTOs, so be it.
In your example, a task contains a user. One probably doesn't need a full user object there, maybe just the name of the user that is assigned the task. We don't need the rest of the user properties.
Let's say you want to reassign a task to a different user, one may be tempted to pass a full user object and a full task object during the re-assignment post. But, what is really needed is just the task Id and the user Id. Those are the only two pieces of information needed to re-assign a task, so model the DTO as such. This usually means there is a separate DTO for every rest call if your striving for a lean DTO model.
Also, sometimes one may need inheritance/composition. Let's say one has a job. A job has multiple tasks. In that case, getting a job may also return the list of tasks for the job as well. So, there is no rule against composition. It depends on what is being modeled.
Best Answer
In general, you want to accept as abstract a type as possible, and return as concrete a type as possible, but the situation you came across isn't really a question of abstract vs. concrete types. If you want the caller to be responsible for making sure an argument is serializable, that needs to be specified in the interface. That means requiring both
IList
and something likeISerializable
.Alternately, you could implement the serialization yourself using just the
IList
interface. However, not allILists
are serializable. How would you serialize an infinite list, for example?That being said, the C# syntax for parameters that require multiple interfaces is inane. There's a YAGNI argument to be made that do you really need to support everything that implements
IList
? Is it worth the trade off in readability?Design principles need to be balanced, so sometimes it's okay to give up a little abstraction in order to gain clarity.