Betwixt only allows the registration of a single object/string converter strategy class. This class serves as a mediator to route conversion calls to helper classes depending based on type. Converters are registered and by deregistered via calls to the register and deregister methods, respectively, and resolved via the resolve method. Only one ObjectStringConverter can be registered per class at any given time. If there is no ObjectStringConverter registered for a given class, then the resolve method checks to see if there is an ObjectStringConverter registered for its super class or any of its interfaces (recursively). The first ObjectStringConverter found in the class hierarchy is used. (Note that if the class implements many interfaces, and there are converters for more than one of those interfaces, the resulting behavior will be undefined.)

import java.util.*;
import org.apache.commons.betwixt.expression.*;
import org.apache.commons.betwixt.strategy.*;

/**
 * 
 *
 * @author Jesse Sweetland
 */
public class CustomObjectStringConverter extends DefaultObjectStringConverter {
    private final Map<Class, ObjectStringConverter> _converters = new HashMap<Class, ObjectStringConverter>();
    
    public void register(ObjectStringConverter converter, Class forType) {
        _converters.put(forType, converter);
    }
    
    public void deregister(Class forType) {
        _converters.remove(forType);
    }

    public ObjectStringConverter resolve(Class forType) {
        int minDistance = Integer.MAX_VALUE;
        ObjectStringConverter converter = null;
        for(Map.Entry<Class, ObjectStringConverter> entry: _converters.entrySet()) {
            int distance = getDistance(entry.getKey(), forType);
            if((distance >= 0) && (distance < minDistance)) {
                minDistance = distance;
                converter = entry.getValue();
            }
        }
        return converter;
    }
    
    private int getDistance(Class superClass, Class type) {
        if(superClass.isAssignableFrom(type)) {
            Class temp = type;
            int distance = 0;
            while(temp != null) {
                if(temp.equals(superClass)) return distance;
                for(Class ifc: temp.getInterfaces()) {
                    if(ifc.equals(superClass)) return distance;
                }
                distance++;
                temp = temp.getSuperclass();
            }
        }
        return -1;
    }
    
    public String objectToString(Object object, Class type, Context context) {
        if(object == null) return null;
        ObjectStringConverter converter = resolve(type);
        if(converter != null) {
            return converter.objectToString(object, type, context);
        } else {
            return super.objectToString(object, type, context);
        }
    }
    
    public Object stringToObject(String value, Class type, Context context) {
        if(value == null) return null;
        ObjectStringConverter converter = resolve(type);
        if(converter != null) {
            return converter.stringToObject(value, type, context);
        } else {
            return super.stringToObject(value, type, context);
        }
    }    
}

Example:

StringWriter sw = new StringWriter();
BeanWriter bw = new BeanWriter(sw);
CustomObjectStringConverter osc = new CustomObjectStringConverter();
osc.register(new EnumObjectStringConverter(), Enum.class);
osc.register(new DateObjectStringConverter(), Date.class);
bw.getBindingConfiguration().setObjectStringConverter(osc);
  • No labels