package org.docx4j.utils;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
/** @author alberto */
public abstract class AbstractTraversalUtilVisitorCallback extends TraversalUtil.CallbackImpl {
/**
* Get the actual type arguments a child class has used to extend a generic base class.
* based on http://www.artima.com/weblogs/viewpost.jsp?thread=208860
*/
protected Class findClassParameter(Class childClass) {
Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
while (! getTypeClass(type).equals(TraversalUtilVisitor.class)) {
if (type instanceof Class) {
// there is no useful information for us in raw types, so just keep going.
type = ((Class) type).getGenericSuperclass();
}
else {
ParameterizedType parameterizedType = (ParameterizedType) type;
Class<?> rawType = (Class)parameterizedType.getRawType();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!rawType.equals(TraversalUtilVisitor.class)) {
type = rawType.getGenericSuperclass();
}
}
}
// finally, for each actual type argument provided to baseClass, determine (if possible)
// the raw class for that type argument.
Type baseType =
(type instanceof Class ?
((Class)type).getTypeParameters()[0] :
((ParameterizedType)type).getActualTypeArguments()[0]);
// resolve types by chasing down type variables.
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
return getTypeClass(baseType);
}
protected Class getTypeClass(Type type) {
return (type instanceof Class ?
(Class)type :
(type instanceof ParameterizedType ?
getTypeClass(((ParameterizedType) type).getRawType()) : null));
}
// Depth first
@Override
public void walkJAXBElements(Object parent) {
List children = getChildren(parent);
if (children != null) {
for (Object o : children) {
// if its wrapped in javax.xml.bind.JAXBElement, get its
// value; this is ok, provided the results of the Callback
// won't be marshalled
o = XmlUtils.unwrap(o);
this.apply(o, parent, children);
if (this.shouldTraverse(o)) {
walkJAXBElements(o);
}
}
}
}
@Override
public final List<Object> apply(Object o) {
throw new UnsupportedOperationException("Invalid apply method - Abstract traversal util should use apply(Object child, Object parent, List siblings)");
}
protected abstract List<Object> apply(Object child, Object parent, List children);
}