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

org.codehaus.jackson.map.type.TypeBindings Maven / Gradle / Ivy

Go to download

Data Mapper package is a high-performance data binding package built on Jackson JSON processor

There is a newer version: 1.9.13
Show newest version
package org.codehaus.jackson.map.type;

import java.lang.reflect.*;
import java.util.*;

import org.codehaus.jackson.type.JavaType;

/**
 * Helper class used for resolving type parameters for given class
 * 
 * @since 1.5
 */
public class TypeBindings
{
    /**
     * Marker to use for (temporarily) unbound references.
     */
    public final static JavaType UNBOUND = new SimpleType(Object.class);

    /**
     * Context type used for resolving all types, if specified. May be null,
     * in which case {@link #_contextClass} is used instead.
     */
    protected final JavaType _contextType;

    /**
     * Specific class to use for resolving all types, for methods and fields
     * class and its superclasses and -interfaces contain.
     */
    protected final Class _contextClass;

    /**
     * Lazily-instantiated bindings of resolved type parameters
     */
    protected Map _bindings;

    /**
     * Also: we may temporarily want to mark certain named types
     * as resolved (but without exact type); if so, we'll just store
     * names here.
     */
    protected HashSet _placeholders;
    
    public TypeBindings(Class cc) {
        _contextClass = cc;
        _contextType = null;
    }

    public TypeBindings(JavaType type)
    {
        _contextType = type;
        _contextClass = type.getRawClass();
    }

    public int getBindingCount() {
        if (_bindings == null) {
            _resolve();
        }
        return _bindings.size();
    }
    
    public JavaType findType(String name)
    {
        if (_bindings == null) {
            _resolve();
        }
        JavaType t = _bindings.get(name);
        if (t == null) {
            if (_placeholders != null && _placeholders.contains(name)) {
                t = UNBOUND;
            } else {
                // Should we throw an exception or just return null?
                throw new IllegalArgumentException("Type variable '"+name
                        +"' can not be resolved (with context of class "+_contextClass.getName()+")");
                //t = UNBOUND;                
            }
        }
        return t;
    }

    /*
    /*******************************************************************8
    /* Internal methods
    /*******************************************************************8
     */
    
    protected void _resolve()
    {
        _resolveBindings(_contextClass);

        // finally: may have root level type info too
        if (_contextType != null) {
            int count = _contextType.containedTypeCount();
            if (count > 0) {
                if (_bindings == null) {
                    _bindings = new HashMap();
                }
                for (int i = 0; i < count; ++i) {
                    String name = _contextType.containedTypeName(i);
                    JavaType type = _contextType.containedType(i);
                    _bindings.put(name, type);
                }
            }
        }

        // nothing bound? mark with empty map to prevent further calls
        if (_bindings == null) {
            _bindings = Collections.emptyMap();
        }
    }

    public void _addPlaceholder(String name) {
        if (_placeholders == null) {
            _placeholders = new HashSet();
        }
        _placeholders.add(name);
    }

    protected void _resolveBindings(Type t)
    {
        if (t == null) return;
        
        Class raw;
        if (t instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) t;
            Type[] args = pt.getActualTypeArguments();
            if (args  != null && args.length > 0) {
                Class rawType = (Class) pt.getRawType();    
                TypeVariable[] vars = rawType.getTypeParameters();
                if (vars.length != args.length) {
                    throw new IllegalArgumentException("Strange parametrized type (in class "+rawType.getName()+"): number of type arguments != number of type parameters ("+args.length+" vs "+vars.length+")");
                }
                for (int i = 0, len = args.length; i < len; ++i) {
                    TypeVariable var = vars[i];
                    String name = var.getName();
                    if (_bindings == null) {
                        _bindings = new HashMap();
                    } else {
                        /* 24-Mar-2010, tatu: Better ensure that we do not overwrite something
                         *  collected earlier (since we descend towards super-classes):
                         */
                        if (_bindings.containsKey(name)) continue;
                    }
                    // first: add a placeholder to prevent infinite loops
                    _addPlaceholder(name);
                    // then resolve type
                    _bindings.put(name, TypeFactory.instance._fromType(args[i], this));
                }
            }
            raw = (Class)pt.getRawType();
        } else if (t instanceof Class) {
            raw = (Class) t;
            /* 24-Mar-2010, tatu: Can not have true generics definitions, but can
             *   have lower bounds ("") in declaration itself
             */
            TypeVariable[] vars = raw.getTypeParameters();
            if (vars != null && vars.length > 0) {
                for (TypeVariable var : vars) {
                    String name = var.getName();
                    Type varType = var.getBounds()[0];
                    if (varType != null) {
                        if (_bindings == null) {
                            _bindings = new HashMap();
                        } else { // and no overwriting...
                            if (_bindings.containsKey(name)) continue;
                        }
                        _addPlaceholder(name); // to prevent infinite loops
                        _bindings.put(name, TypeFactory.instance._fromType(varType, this));
                    }
                }
            }
        } else { // probably can't be any of these... so let's skip for now
            //if (type instanceof GenericArrayType) {
            //if (type instanceof TypeVariable) {
            // if (type instanceof WildcardType) {
            return;
        }
        // but even if it's not a parameterized type, its super types may be:
        _resolveBindings(raw.getGenericSuperclass());
        for (Type intType : raw.getGenericInterfaces()) {
            _resolveBindings(intType);
        }
    }

    @Override
    public String toString()
    {
        if (_bindings == null) {
            _resolve();
        }
        StringBuilder sb = new StringBuilder("[TypeBindings for ");
        if (_contextType != null) {
            sb.append(_contextType.toString());
        } else {
            sb.append(_contextClass.getName());
        }
        sb.append(": ").append(_bindings).append("]");
        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy