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;
 
This class can be used by any generic super class to resolve one of its type parameter to the actual type argument used by the subclass, provided the type argument is carried on the class declaration.

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

  
Returns a new TypeResolver with type variables in mapFrom mapping to types in type. Either mapFrom is a type variable, or mapFrom and mapTo are both java.lang.reflect.ParameterizedType of the same raw type, or java.lang.reflect.GenericArrayType of the same component type. Caller needs to ensure this before calling.
 
   final TypeResolver where(Type mapFromType mapTo) {
     Map<TypeVariable<?>, Typemappings = Maps.newHashMap();
     populateTypeMappings(mappingsmapFrommapTo);
     return where(mappings);
   }
 
   private static void populateTypeMappings(
       Map<TypeVariable<?>, TypemappingsType fromType to) {
     if (from instanceof TypeVariable) {
       mappings.put((TypeVariable<?>) fromto);
     } else if (from instanceof GenericArrayType) {
       populateTypeMappings(mappings,
           ((GenericArrayTypefrom).getGenericComponentType(), Types.getComponentType(to));
     } else if (from instanceof ParameterizedType) {
       Type[] fromArgs = ((ParameterizedTypefrom).getActualTypeArguments();
       Type[] toArgs = ((ParameterizedTypeto).getActualTypeArguments();
       checkArgument(fromArgs.length == toArgs.length);
       for (int i = 0; i < fromArgs.lengthi++) {
         populateTypeMappings(mappingsfromArgs[i], toArgs[i]);
      }
    }
  }
  
  
Resolves all type variables in type and all downstream types and returns a corresponding type with type variables resolved.
  final Type resolve(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(
          resolve(wildcardType.getLowerBounds()),
          resolve(wildcardType.getUpperBounds()));
    } else {
      // if Class<?>, no resolution needed, we are done.
      return type;
    }
  } 
  
  private Type[] resolve(Type[] types) {
    Type[] result = new Type[types.length];
    for (int i = 0; i < types.lengthi++) {
      result[i] = resolve(types[i]);
    }
    return result;
  }
  
    Type componentType = resolve(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.resolve(bounds));
    }
    return guardedResolver.resolve(type); // in case the type is yet another type variable.
  }
  
    Type owner = type.getOwnerType();
    Type resolvedOwner = (owner == null) ? null : resolve(owner);
    Type resolvedRawType = resolve(type.getRawType());
    
    Type[] vars = type.getActualTypeArguments();
    Type[] resolvedArgs = new Type[vars.length];
    for (int i = 0; i < vars.lengthi++) {
      resolvedArgs[i] = resolve(vars[i]);
    }
    return Types.newParameterizedTypeWithOwner(
        resolvedOwner, (Class<?>) resolvedRawTyperesolvedArgs);
  }
  
  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