1 /* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.reflect.generics.reflectiveObjects; 27 28 import sun.reflect.generics.tree.FieldTypeSignature; 29 30 import java.lang.reflect.MalformedParameterizedTypeException; 31 import java.lang.reflect.Method; 32 import java.lang.reflect.ParameterizedType; 33 import java.lang.reflect.Type; 34 import java.lang.reflect.TypeVariable; 35 import java.util.Arrays; 36 import java.util.StringJoiner; 37 import java.util.Objects; 38 39 /** Implementing class for ParameterizedType interface. */ 40 41 public class ParameterizedTypeImpl implements ParameterizedType { 42 private final Type[] actualTypeArguments; 43 private final Class<?> rawType; 44 private final Type ownerType; 45 46 private ParameterizedTypeImpl(Class<?> rawType, 47 Type[] actualTypeArguments, 48 Type ownerType) { 49 this.actualTypeArguments = actualTypeArguments; 50 this.rawType = rawType; 51 this.ownerType = (ownerType != null) ? ownerType : rawType.getDeclaringClass(); 52 validateConstructorArguments(); 53 } 54 55 private void validateConstructorArguments() { 56 TypeVariable<?>[] formals = rawType.getTypeParameters(); 57 // check correct arity of actual type args 58 if (formals.length != actualTypeArguments.length){ 59 throw new MalformedParameterizedTypeException(); 60 } 61 for (int i = 0; i < actualTypeArguments.length; i++) { 62 // check actuals against formals' bounds 63 } 64 } 65 66 /** 67 * Static factory. Given a (generic) class, actual type arguments 68 * and an owner type, creates a parameterized type. 69 * This class can be instantiated with a a raw type that does not 70 * represent a generic type, provided the list of actual type 71 * arguments is empty. 72 * If the ownerType argument is null, the declaring class of the 73 * raw type is used as the owner type. 74 * <p> This method throws a MalformedParameterizedTypeException 75 * under the following circumstances: 76 * If the number of actual type arguments (i.e., the size of the 77 * array {@code typeArgs}) does not correspond to the number of 78 * formal type arguments. 79 * If any of the actual type arguments is not an instance of the 80 * bounds on the corresponding formal. 81 * @param rawType the Class representing the generic type declaration being 82 * instantiated 83 * @param actualTypeArguments a (possibly empty) array of types 84 * representing the actual type arguments to the parameterized type 85 * @param ownerType the enclosing type, if known. 86 * @return An instance of {@code ParameterizedType} 87 * @throws MalformedParameterizedTypeException if the instantiation 88 * is invalid 89 */ 90 public static ParameterizedTypeImpl make(Class<?> rawType, 91 Type[] actualTypeArguments, 92 Type ownerType) { 93 return new ParameterizedTypeImpl(rawType, actualTypeArguments, 94 ownerType); 95 } 96 97 98 /** 99 * Returns an array of {@code Type} objects representing the actual type 100 * arguments to this type. 101 * 102 * <p>Note that in some cases, the returned array be empty. This can occur 103 * if this type represents a non-parameterized type nested within 104 * a parameterized type. 105 * 106 * @return an array of {@code Type} objects representing the actual type 107 * arguments to this type 108 * @throws TypeNotPresentException if any of the 109 * actual type arguments refers to a non-existent type declaration 110 * @throws MalformedParameterizedTypeException if any of the 111 * actual type parameters refer to a parameterized type that cannot 112 * be instantiated for any reason 113 * @since 1.5 114 */ 115 public Type[] getActualTypeArguments() { 116 return actualTypeArguments.clone(); 117 } 118 119 /** 120 * Returns the {@code Type} object representing the class or interface 121 * that declared this type. 122 * 123 * @return the {@code Type} object representing the class or interface 124 * that declared this type 125 */ 126 public Class<?> getRawType() { 127 return rawType; 128 } 129 130 131 /** 132 * Returns a {@code Type} object representing the type that this type 133 * is a member of. For example, if this type is {@code O<T>.I<S>}, 134 * return a representation of {@code O<T>}. 135 * 136 * <p>If this type is a top-level type, {@code null} is returned. 137 * 138 * @return a {@code Type} object representing the type that 139 * this type is a member of. If this type is a top-level type, 140 * {@code null} is returned 141 * @throws TypeNotPresentException if the owner type 142 * refers to a non-existent type declaration 143 * @throws MalformedParameterizedTypeException if the owner type 144 * refers to a parameterized type that cannot be instantiated 145 * for any reason 146 * 147 */ 148 public Type getOwnerType() { 149 return ownerType; 150 } 151 152 /* 153 * From the JavaDoc for java.lang.reflect.ParameterizedType 154 * "Instances of classes that implement this interface must 155 * implement an equals() method that equates any two instances 156 * that share the same generic type declaration and have equal 157 * type parameters." 158 */ 159 @Override 160 public boolean equals(Object o) { 161 if (o instanceof ParameterizedType) { 162 // Check that information is equivalent 163 ParameterizedType that = (ParameterizedType) o; 164 165 if (this == that) 166 return true; 167 168 Type thatOwner = that.getOwnerType(); 169 Type thatRawType = that.getRawType(); 170 171 if (false) { // Debugging 172 boolean ownerEquality = (ownerType == null ? 173 thatOwner == null : 174 ownerType.equals(thatOwner)); 175 boolean rawEquality = (rawType == null ? 176 thatRawType == null : 177 rawType.equals(thatRawType)); 178 179 boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone 180 that.getActualTypeArguments()); 181 for (Type t : actualTypeArguments) { 182 System.out.printf("\t\t%s%s%n", t, t.getClass()); 183 } 184 185 System.out.printf("\towner %s\traw %s\ttypeArg %s%n", 186 ownerEquality, rawEquality, typeArgEquality); 187 return ownerEquality && rawEquality && typeArgEquality; 188 } 189 190 return 191 Objects.equals(ownerType, thatOwner) && 192 Objects.equals(rawType, thatRawType) && 193 Arrays.equals(actualTypeArguments, // avoid clone 194 that.getActualTypeArguments()); 195 } else 196 return false; 197 } 198 199 @Override 200 public int hashCode() { 201 return 202 Arrays.hashCode(actualTypeArguments) ^ 203 Objects.hashCode(ownerType) ^ 204 Objects.hashCode(rawType); 205 } 206 207 public String toString() { 208 StringBuilder sb = new StringBuilder(); 209 210 if (ownerType != null) { 211 sb.append(ownerType.getTypeName()); 212 213 sb.append("."); 214 215 if (ownerType instanceof ParameterizedTypeImpl) { 216 // Find simple name of nested type by removing the 217 // shared prefix with owner. 218 sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$", 219 "")); 220 } else 221 sb.append(rawType.getName()); 222 } else 223 sb.append(rawType.getName()); 224 225 if (actualTypeArguments != null) { 226 StringJoiner sj = new StringJoiner(", ", "<", ">"); 227 sj.setEmptyValue(""); 228 for(Type t: actualTypeArguments) { 229 sj.add(t.getTypeName()); 230 } 231 sb.append(sj.toString()); 232 } 233 234 return sb.toString(); 235 } 236 }