1/* 2 * Copyright (C) 2013 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.reflect; 18 19import com.google.common.collect.Sets; 20 21import java.lang.reflect.GenericArrayType; 22import java.lang.reflect.ParameterizedType; 23import java.lang.reflect.Type; 24import java.lang.reflect.TypeVariable; 25import java.lang.reflect.WildcardType; 26import java.util.Set; 27 28import javax.annotation.concurrent.NotThreadSafe; 29 30/** 31 * Based on what a {@link Type} is, dispatch it to the corresponding {@code visit*} method. By 32 * default, no recursion is done for type arguments or type bounds. But subclasses can opt to do 33 * recursion by calling {@link #visit} for any {@code Type} while visitation is in progress. For 34 * example, this can be used to reject wildcards or type variables contained in a type as in: 35 * 36 * <pre> {@code 37 * new TypeVisitor() { 38 * protected void visitParameterizedType(ParameterizedType t) { 39 * visit(t.getOwnerType()); 40 * visit(t.getActualTypeArguments()); 41 * } 42 * protected void visitGenericArrayType(GenericArrayType t) { 43 * visit(t.getGenericComponentType()); 44 * } 45 * protected void visitTypeVariable(TypeVariable<?> t) { 46 * throw new IllegalArgumentException("Cannot contain type variable."); 47 * } 48 * protected void visitWildcardType(WildcardType t) { 49 * throw new IllegalArgumentException("Cannot contain wildcard type."); 50 * } 51 * }.visit(type);}</pre> 52 * 53 * <p>One {@code Type} is visited at most once. The second time the same type is visited, it's 54 * ignored by {@link #visit}. This avoids infinite recursion caused by recursive type bounds. 55 * 56 * <p>This class is <em>not</em> thread safe. 57 * 58 * @author Ben Yu 59 */ 60@NotThreadSafe 61abstract class TypeVisitor { 62 63 private final Set<Type> visited = Sets.newHashSet(); 64 65 /** 66 * Visits the given types. Null types are ignored. This allows subclasses to call 67 * {@code visit(parameterizedType.getOwnerType())} safely without having to check nulls. 68 */ 69 public final void visit(Type... types) { 70 for (Type type : types) { 71 if (type == null || !visited.add(type)) { 72 // null owner type, or already visited; 73 continue; 74 } 75 boolean succeeded = false; 76 try { 77 if (type instanceof TypeVariable) { 78 visitTypeVariable((TypeVariable<?>) type); 79 } else if (type instanceof WildcardType) { 80 visitWildcardType((WildcardType) type); 81 } else if (type instanceof ParameterizedType) { 82 visitParameterizedType((ParameterizedType) type); 83 } else if (type instanceof Class) { 84 visitClass((Class<?>) type); 85 } else if (type instanceof GenericArrayType) { 86 visitGenericArrayType((GenericArrayType) type); 87 } else { 88 throw new AssertionError("Unknown type: " + type); 89 } 90 succeeded = true; 91 } finally { 92 if (!succeeded) { // When the visitation failed, we don't want to ignore the second. 93 visited.remove(type); 94 } 95 } 96 } 97 } 98 99 void visitClass(Class<?> t) {} 100 void visitGenericArrayType(GenericArrayType t) {} 101 void visitParameterizedType(ParameterizedType t) {} 102 void visitTypeVariable(TypeVariable<?> t) {} 103 void visitWildcardType(WildcardType t) {} 104} 105