package com.google.code.joto.value2java;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import com.google.code.joto.util.PriorityList;
import com.google.code.joto.value2java.converters.VHToStmtConverterLookupUtils;
import com.thoughtworks.xstream.converters.ConversionException;
/**
* helper class for configuring custom Converter per types, on looking up them
*
*/
public class VHToStmtConverterLookup {
/**
* ordered list of user-defined converters
*/
private PriorityList<ObjectVHToStmtConverter> objConverters =
new PriorityList<ObjectVHToStmtConverter>();
/**
* ordered list of link object->object converters
*/
private PriorityList<RefObjectVHToStmtConverter> refObjConverters =
new PriorityList<RefObjectVHToStmtConverter>();
/** lazy computed field, from objConverters */
private transient Map<Class<?>,ObjectVHToStmtConverter> cachedTypeToConverter =
new HashMap<Class<?>,ObjectVHToStmtConverter>();
/** lazy computed field, from objConverters */
private transient Map<RefClassToClassKey,RefObjectVHToStmtConverter> cachedRefKeyToRefObjConverter =
new HashMap<RefClassToClassKey,RefObjectVHToStmtConverter>();
//-------------------------------------------------------------------------
public VHToStmtConverterLookup(boolean registerDefaults) {
if (registerDefaults) {
VHToStmtConverterLookupUtils.registerDefaultConverters(this);
}
}
//-------------------------------------------------------------------------
public void registerConverter(ObjectVHToStmtConverter p, int priority) {
objConverters.add(p, priority);
if (cachedTypeToConverter != null) {
cachedTypeToConverter.clear(); // clear corresponding cache results
}
}
public void registerLinkConverter(RefObjectVHToStmtConverter p, int priority) {
refObjConverters.add(p, priority);
if (cachedRefKeyToRefObjConverter != null) {
cachedRefKeyToRefObjConverter.clear(); // clear corresponding cache results
}
}
public ObjectVHToStmtConverter lookupConverter(Class<?> type) {
ObjectVHToStmtConverter res = cachedTypeToConverter.get(type);
if (res == null) {
for(ObjectVHToStmtConverter elt : objConverters) {
if (elt.canConvert(type)) {
cachedTypeToConverter.put(type, elt);
res = elt;
break;
}
}
if (res == null) {
res = null; // throw new ConversionException("No converter specified for " + type);
// => TODO standard Bean converter ...
}
}
return res;
}
public RefObjectVHToStmtConverter lookupConverter(Class<?> from, String[] path, Class<?> to) {
RefClassToClassKey key = new RefClassToClassKey(from, path, to);
RefObjectVHToStmtConverter res = cachedRefKeyToRefObjConverter.get(key);
if (res == null) {
for(RefObjectVHToStmtConverter elt : refObjConverters) {
if (elt.canConvert(from, path, to)) {
cachedRefKeyToRefObjConverter.put(key, elt);
res = elt;
break;
}
}
if (res == null) {
throw new ConversionException("No converter specified for link " + from + " -" + path + "->" + to);
}
}
return res;
}
// -------------------------------------------------------------------------
/**
* internal
*/
private static class RefClassToClassKey {
private final Class<?> fromClass;
private final String[] path;
private final Class<?> toClass;
public RefClassToClassKey(Class<?> fromClass, String[] path, Class<?> toClass) {
super();
this.fromClass = fromClass;
this.path = new String[path.length];
System.arraycopy(path, 0, this.path, 0, path.length);
this.toClass = toClass;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((fromClass == null) ? 0 : fromClass.hashCode());
result = prime * result + Arrays.hashCode(path);
result = prime * result
+ ((toClass == null) ? 0 : toClass.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RefClassToClassKey other = (RefClassToClassKey) obj;
if (fromClass == null) {
if (other.fromClass != null)
return false;
} else if (!fromClass.equals(other.fromClass))
return false;
if (!Arrays.equals(path, other.path))
return false;
if (toClass == null) {
if (other.toClass != null)
return false;
} else if (!toClass.equals(other.toClass))
return false;
return true;
}
}
}