intelligent mapping of Class keys
I have created a simple API to convert arbitrary objects into human-readable strings. Think of it as a generalized String.valueOf()
functionality.
The API achieves this by selecting an
public interface ObjectFormatter {
public String format(Object object);
public Class getObjectClass();
public boolean offer(Object object);
}
depending on the getClass()
method of the particular object, and then passing the object to the format()
method. Mapping is done through a simple lookup:
Class clazz = object.getClass();
ObjectFormatter formatter = this.formatters.get(clazz);
if(formatter != null)
return formatter;
However, this of course only works in cases where object class and key class are exactly the same, but the API must also be able to map key class derivatives (or implementations, if the key is an interface
) to the same formatter, otherwise I would end up mapping a Throwable
formatter to each possible exception class in my application.
Therefore, when the above lookup fails, my current solution is to walk through the whole map and ask each formatter if it is capable of formatting my object. Yet I'm not too happy with this, and I wonder if there might be a bett开发者_JAVA百科er way.
Well, the strict OOP way with simply overriding toString()
and forgetting about the formatter would work on my own classes but fails at 3rd-party libraries, especially when a particular toString()
implementation does not include the desired information about the object.
You could use the isAssignableFrom API of the java.lang.Class
Also If I were you instead of doing the whole framework myself I would just use the "PropertyEditor Support classes" from Spring (to convert/format a bean into a string property and vice versa) http://static.springsource.org/spring/docs/2.5.x/reference/validation.html
Basically, this is the kind place where a little reflection could help.
- Begin by browsing all the superclasses of your object class by calling
Class.getSuperclass()
but don't forget to stop your super-navigation once Object is reached, as Object superclass is Object. - If no ObjectFormatter was found, you can call
Class.getInterfaces()
to get the list of interfaces implemented by your class. Obviously, calling it on an interface will return the interfaces it extend ...
Then, you have the choice, you can either call (1), then (2) or (preferably) call (2) and aggregate its results, and only if (2) fails, call (1). This way, you'll be more respectfull to your obejct's various contracts.
My quick and dirty idea was that you could just traverse the "clazz"'s inheritance tree and see whether formatters contained them. That way you could add one Throwable formatter and all of the exceptions would get it.
From a proper OOP/inheritance perspective, and assuming you can't modify the actual class because it's a third party, I would probably add an adapter around the third party class that had the methods I wanted. In a previous project, we resisted doing this for awhile, thinking it would be too bulky/ugly, but that just resulted in a lot of hacky workarounds. When we finally bit the bullet and did it, we could go back to regular good design. Just my 2 cents.
精彩评论