Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2009 The Guava Authors
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package com.google.common.reflect;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
 
 import java.util.Map;
 import java.util.Set;
 
 import  javax.annotation.Nullable;

An object of this class encapsulates type mappings from type variables. Mappings are established with where and types are resolved using resolveType.

Note that usually type mappings are already implied by the static type hierarchy (for example, the E type variable declared by class List naturally maps to String in the context of class MyStringList implements List<String>. In such case, prefer to use TypeToken.resolveType since it's simpler and more type safe. This class should only be used when the type mapping isn't implied by the static type hierarchy, but provided through other means such as an annotation or external configuration file.

Author(s):
Ben Yu
 
 class TypeResolver {
 
   private final ImmutableMap<TypeVariable<?>, TypetypeTable;
 
   public TypeResolver() {
     this. = ImmutableMap.of();
   }
 
   private TypeResolver(ImmutableMap<TypeVariable<?>, TypetypeTable) {
     this. = typeTable;
   }
 
   static TypeResolver accordingTo(Type type) {
     return new TypeResolver().where(TypeMappingIntrospector.getTypeMappings(type));
   }

  
Returns a new TypeResolver with type variables in formal mapping to types in actual.

For example, if formal is a TypeVariable T, and actual is String.class, then new TypeResolver().where(formal, actual) will resolveType resolve ParameterizedType List<T> to List<String>, and resolve Map<T, Something> to Map<String, Something> etc. Similarly, formal and actual can be Map<K, V> and Map<String, Integer> respectively, or they can be E[] and String[] respectively, or even any arbitrary combination thereof.

Parameters:
formal The type whose type variables or itself is mapped to other type(s). It's almost always a bug if formal isn't a type variable and contains no type variable. Make sure you are passing the two parameters in the right order.
actual The type that the formal type variable(s) are mapped to. It can be or contain yet other type variables, in which case these type variables will be further resolved if corresponding mappings exist in the current TypeResolver instance.
 
   public final TypeResolver where(Type formalType actual) {
     Map<TypeVariable<?>, Typemappings = Maps.newHashMap();
     populateTypeMappings(mappingsformalactual);
     return where(mappings);
   }

  
Returns a new TypeResolver with variable mapping to type.
 
   final TypeResolver where(Map<? extends TypeVariable<?>, ? extends Typemappings) {
     ImmutableMap.Builder<TypeVariable<?>, Typebuilder = ImmutableMap.builder();
     builder.putAll();
     for (Map.Entry<? extends TypeVariable<?>, ? extends Typemapping : mappings.entrySet()) {
       TypeVariable<?> variable = mapping.getKey();
       Type type = mapping.getValue();
      checkArgument(!variable.equals(type), "Type variable %s bound to itself"variable);
      builder.put(variabletype);
    }
    return new TypeResolver(builder.build());
  }
  private static void populateTypeMappings(
      Map<TypeVariable<?>, TypemappingsType fromType to) {
    if (from.equals(to)) {
      return;
    }
    if (from instanceof TypeVariable) {
      mappings.put((TypeVariable<?>) fromto);
    } else if (from instanceof GenericArrayType) {
      populateTypeMappings(mappings,
          ((GenericArrayTypefrom).getGenericComponentType(),
          checkNonNullArgument(Types.getComponentType(to), "%s is not an array type."to));
    } else if (from instanceof ParameterizedType) {
      ParameterizedType fromParameterizedType = (ParameterizedTypefrom;
      ParameterizedType toParameterizedType = expectArgument(ParameterizedType.classto);
      checkArgument(fromParameterizedType.getRawType().equals(toParameterizedType.getRawType()),
          "Inconsistent raw type: %s vs. %s"fromto);
      Type[] fromArgs = fromParameterizedType.getActualTypeArguments();
      Type[] toArgs = toParameterizedType.getActualTypeArguments();
      checkArgument(fromArgs.length == toArgs.length);
      for (int i = 0; i < fromArgs.lengthi++) {
        populateTypeMappings(mappingsfromArgs[i], toArgs[i]);
      }
    } else if (from instanceof WildcardType) {
      WildcardType fromWildcardType = (WildcardTypefrom;
      WildcardType toWildcardType = expectArgument(WildcardType.classto);
      Type[] fromUpperBounds = fromWildcardType.getUpperBounds();
      Type[] toUpperBounds = toWildcardType.getUpperBounds();
      Type[] fromLowerBounds = fromWildcardType.getLowerBounds();
      Type[] toLowerBounds = toWildcardType.getLowerBounds();
      checkArgument(
          fromUpperBounds.length == toUpperBounds.length
              && fromLowerBounds.length == toLowerBounds.length,
          "Incompatible type: %s vs. %s"fromto);
      for (int i = 0; i < fromUpperBounds.lengthi++) {
        populateTypeMappings(mappingsfromUpperBounds[i], toUpperBounds[i]);
      }
      for (int i = 0; i < fromLowerBounds.lengthi++) {
        populateTypeMappings(mappingsfromLowerBounds[i], toLowerBounds[i]);
      }
    } else {
      throw new IllegalArgumentException("No type mapping from " + from);
    }
  }

  
Resolves all type variables in type and all downstream types and returns a corresponding type with type variables resolved.
  public final Type resolveType(Type type) {
    if (type instanceof TypeVariable) {
      return resolveTypeVariable((TypeVariable<?>) type);
    } else if (type instanceof ParameterizedType) {
      return resolveParameterizedType((ParameterizedTypetype);
    } else if (type instanceof GenericArrayType) {
      return resolveGenericArrayType((GenericArrayTypetype);
    } else if (type instanceof WildcardType) {
      WildcardType wildcardType = (WildcardTypetype;
      return new Types.WildcardTypeImpl(
          resolveTypes(wildcardType.getLowerBounds()),
          resolveTypes(wildcardType.getUpperBounds()));
    } else {
      // if Class<?>, no resolution needed, we are done.
      return type;
    }
  }
  private Type[] resolveTypes(Type[] types) {
    Type[] result = new Type[types.length];
    for (int i = 0; i < types.lengthi++) {
      result[i] = resolveType(types[i]);
    }
    return result;
  }
    Type componentType = resolveType(type.getGenericComponentType());
    return Types.newArrayType(componentType);
  }
  private Type resolveTypeVariable(final TypeVariable<?> var) {
    final TypeResolver unguarded = this;
    TypeResolver guarded = new TypeResolver() {
          TypeVariable<?> intermediateVarTypeResolver guardedResolver) {
        if (intermediateVar.getGenericDeclaration().equals(var.getGenericDeclaration())) {
          return intermediateVar;
        }
        return unguarded.resolveTypeVariable(intermediateVarguardedResolver);
      }
    };
    return resolveTypeVariable(varguarded);
  }

  
Resolves var using the encapsulated type mapping. If it maps to yet another non-reified type, guardedResolver is used to do further resolution, which doesn't try to resolve any type variable on generic declarations that are already being resolved.
  Type resolveTypeVariable(TypeVariable<?> varTypeResolver guardedResolver) {
    Type type = .get(var);
    if (type == null) {
      Type[] bounds = var.getBounds();
      if (bounds.length == 0) {
        return var;
      }
      return Types.newTypeVariable(
          var.getGenericDeclaration(),
          var.getName(),
          guardedResolver.resolveTypes(bounds));
    }
    return guardedResolver.resolveType(type); // in case the type is yet another type variable.
  }
    Type owner = type.getOwnerType();
    Type resolvedOwner = (owner == null) ? null : resolveType(owner);
    Type resolvedRawType = resolveType(type.getRawType());
    Type[] vars = type.getActualTypeArguments();
    Type[] resolvedArgs = new Type[vars.length];
    for (int i = 0; i < vars.lengthi++) {
      resolvedArgs[i] = resolveType(vars[i]);
    }
    return Types.newParameterizedTypeWithOwner(
        resolvedOwner, (Class<?>) resolvedRawTyperesolvedArgs);
  }
  private static <T> T checkNonNullArgument(T argString formatObject... messageParams) {
    checkArgument(arg != nullformatmessageParams);
    return arg;
  }
  private static <T> T expectArgument(Class<T> typeObject arg) {
    try {
      return type.cast(arg);
    } catch (ClassCastException e) {
      throw new IllegalArgumentException(arg + " is not a " + type.getSimpleName());
    }
  }
  private static final class TypeMappingIntrospector {
    private static final WildcardCapturer wildcardCapturer = new WildcardCapturer();
    private final Map<TypeVariable<?>, Typemappings = Maps.newHashMap();
    private final Set<TypeintrospectedTypes = Sets.newHashSet();

    
Returns type mappings using type parameters and type arguments found in the generic superclass and the super interfaces of contextClass.
        Type contextType) {
      TypeMappingIntrospector introspector = new TypeMappingIntrospector();
      introspector.introspect(.capture(contextType));
      return ImmutableMap.copyOf(introspector.mappings);
    }
    private void introspect(Type type) {
      if (!.add(type)) {
        return;
      }
      if (type instanceof ParameterizedType) {
      } else if (type instanceof Class) {
        introspectClass((Class<?>) type);
      } else if (type instanceof TypeVariable) {
        for (Type bound : ((TypeVariable<?>) type).getBounds()) {
          introspect(bound);
        }
      } else if (type instanceof WildcardType) {
        for (Type bound : ((WildcardTypetype).getUpperBounds()) {
          introspect(bound);
        }
      }
    }
    private void introspectClass(Class<?> clazz) {
      introspect(clazz.getGenericSuperclass());
      for (Type interfaceType : clazz.getGenericInterfaces()) {
        introspect(interfaceType);
      }
    }
    private void introspectParameterizedType(
        ParameterizedType parameterizedType) {
      Class<?> rawClass = (Class<?>) parameterizedType.getRawType();
      TypeVariable<?>[] vars = rawClass.getTypeParameters();
      Type[] typeArgs = parameterizedType.getActualTypeArguments();
      checkState(vars.length == typeArgs.length);
      for (int i = 0; i < vars.lengthi++) {
        map(vars[i], typeArgs[i]);
      }
      introspectClass(rawClass);
      introspect(parameterizedType.getOwnerType());
    }
    private void map(final TypeVariable<?> varfinal Type arg) {
      if (.containsKey(var)) {
        // Mapping already established
        // This is possible when following both superClass -> enclosingClass
        // and enclosingclass -> superClass paths.
        // Since we follow the path of superclass first, enclosing second,
        // superclass mapping should take precedence.
        return;
      }
      // First, check whether var -> arg forms a cycle
      for (Type t = argt != nullt = .get(t)) {
        if (var.equals(t)) {
          // cycle detected, remove the entire cycle from the mapping so that
          // each type variable resolves deterministically to itself.
          // Otherwise, a F -> T cycle will end up resolving both F and T
          // nondeterministically to either F or T.
          for (Type x = argx != nullx = .remove(x)) {}
          return;
        }
      }
      .put(vararg);
    }
  }
  // This is needed when resolving types against a context with wildcards
  // For example:
  // class Holder<T> {
  //   void set(T data) {...}
  // }
  // Holder<List<?>> should *not* resolve the set() method to set(List<?> data).
  // Instead, it should create a capture of the wildcard so that set() rejects any List<T>.
  private static final class WildcardCapturer {
    private final AtomicInteger id = new AtomicInteger();
    Type capture(Type type) {
      checkNotNull(type);
      if (type instanceof Class) {
        return type;
      }
      if (type instanceof TypeVariable) {
        return type;
      }
      if (type instanceof GenericArrayType) {
        GenericArrayType arrayType = (GenericArrayTypetype;
        return Types.newArrayType(capture(arrayType.getGenericComponentType()));
      }
      if (type instanceof ParameterizedType) {
        ParameterizedType parameterizedType = (ParameterizedTypetype;
        return Types.newParameterizedTypeWithOwner(
            captureNullable(parameterizedType.getOwnerType()),
            (Class<?>) parameterizedType.getRawType(),
            capture(parameterizedType.getActualTypeArguments()));
      }
      if (type instanceof WildcardType) {
        WildcardType wildcardType = (WildcardTypetype;
        Type[] lowerBounds = wildcardType.getLowerBounds();
        if (lowerBounds.length == 0) { // ? extends something changes to capture-of
          Type[] upperBounds = wildcardType.getUpperBounds();
          String name = "capture#" + .incrementAndGet() + "-of ? extends "
              + Joiner.on('&').join(upperBounds);
          return Types.newTypeVariable(
              WildcardCapturer.classnamewildcardType.getUpperBounds());
        } else {
          // TODO(benyu): handle ? super T somehow.
          return type;
        }
      }
      throw new AssertionError("must have been one of the known types");
    }
    private Type captureNullable(@Nullable Type type) {
      if (type == null) {
        return null;
      }
      return capture(type);
    }
    private Type[] capture(Type[] types) {
      Type[] result = new Type[types.length];
      for (int i = 0; i < types.lengthi++) {
        result[i] = capture(types[i]);
      }
      return result;
    }
  }
New to GrepCode? Check out our FAQ X