All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.docx4j.utils.AbstractTraversalUtilVisitorCallback Maven / Gradle / Ivy

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 resolvedTypes = new HashMap();
    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 apply(Object o) {
		throw new UnsupportedOperationException("Invalid apply method - Abstract traversal util should use apply(Object child, Object parent, List siblings)");
	}
	
	protected abstract List apply(Object child, Object parent, List children);

}