/* * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.reflect.generics.reflectiveObjects; import sun.reflect.generics.tree.FieldTypeSignature; import java.lang.reflect.MalformedParameterizedTypeException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.Arrays; import java.util.Objects; /** Implementing class for ParameterizedType interface. */ public class ParameterizedTypeImpl implements ParameterizedType { private final Type[] actualTypeArguments; private final Class rawType; private final Type ownerType; private ParameterizedTypeImpl(Class rawType, Type[] actualTypeArguments, Type ownerType) { this.actualTypeArguments = actualTypeArguments; this.rawType = rawType; this.ownerType = (ownerType != null) ? ownerType : rawType.getDeclaringClass(); validateConstructorArguments(); } private void validateConstructorArguments() { TypeVariable[] formals = rawType.getTypeParameters(); // check correct arity of actual type args if (formals.length != actualTypeArguments.length){ throw new MalformedParameterizedTypeException(); } for (int i = 0; i < actualTypeArguments.length; i++) { // check actuals against formals' bounds } } /** * Static factory. Given a (generic) class, actual type arguments * and an owner type, creates a parameterized type. * This class can be instantiated with a a raw type that does not * represent a generic type, provided the list of actual type * arguments is empty. * If the ownerType argument is null, the declaring class of the * raw type is used as the owner type. *

This method throws a MalformedParameterizedTypeException * under the following circumstances: * If the number of actual type arguments (i.e., the size of the * array {@code typeArgs}) does not correspond to the number of * formal type arguments. * If any of the actual type arguments is not an instance of the * bounds on the corresponding formal. * @param rawType the Class representing the generic type declaration being * instantiated * @param actualTypeArguments a (possibly empty) array of types * representing the actual type arguments to the parameterized type * @param ownerType the enclosing type, if known. * @return An instance of {@code ParameterizedType} * @throws MalformedParameterizedTypeException if the instantiation * is invalid */ public static ParameterizedTypeImpl make(Class rawType, Type[] actualTypeArguments, Type ownerType) { return new ParameterizedTypeImpl(rawType, actualTypeArguments, ownerType); } /** * Returns an array of {@code Type} objects representing the actual type * arguments to this type. * *

Note that in some cases, the returned array be empty. This can occur * if this type represents a non-parameterized type nested within * a parameterized type. * * @return an array of {@code Type} objects representing the actual type * arguments to this type * @throws TypeNotPresentException if any of the * actual type arguments refers to a non-existent type declaration * @throws MalformedParameterizedTypeException if any of the * actual type parameters refer to a parameterized type that cannot * be instantiated for any reason * @since 1.5 */ public Type[] getActualTypeArguments() { return actualTypeArguments.clone(); } /** * Returns the {@code Type} object representing the class or interface * that declared this type. * * @return the {@code Type} object representing the class or interface * that declared this type */ public Class getRawType() { return rawType; } /** * Returns a {@code Type} object representing the type that this type * is a member of. For example, if this type is {@code O.I}, * return a representation of {@code O}. * *

If this type is a top-level type, {@code null} is returned. * * @return a {@code Type} object representing the type that * this type is a member of. If this type is a top-level type, * {@code null} is returned * @throws TypeNotPresentException if the owner type * refers to a non-existent type declaration * @throws MalformedParameterizedTypeException if the owner type * refers to a parameterized type that cannot be instantiated * for any reason * */ public Type getOwnerType() { return ownerType; } /* * From the JavaDoc for java.lang.reflect.ParameterizedType * "Instances of classes that implement this interface must * implement an equals() method that equates any two instances * that share the same generic type declaration and have equal * type parameters." */ @Override public boolean equals(Object o) { if (o instanceof ParameterizedType) { // Check that information is equivalent ParameterizedType that = (ParameterizedType) o; if (this == that) return true; Type thatOwner = that.getOwnerType(); Type thatRawType = that.getRawType(); if (false) { // Debugging boolean ownerEquality = (ownerType == null ? thatOwner == null : ownerType.equals(thatOwner)); boolean rawEquality = (rawType == null ? thatRawType == null : rawType.equals(thatRawType)); boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone that.getActualTypeArguments()); for (Type t : actualTypeArguments) { System.out.printf("\t\t%s%s%n", t, t.getClass()); } System.out.printf("\towner %s\traw %s\ttypeArg %s%n", ownerEquality, rawEquality, typeArgEquality); return ownerEquality && rawEquality && typeArgEquality; } return Objects.equals(ownerType, thatOwner) && Objects.equals(rawType, thatRawType) && Arrays.equals(actualTypeArguments, // avoid clone that.getActualTypeArguments()); } else return false; } @Override public int hashCode() { return Arrays.hashCode(actualTypeArguments) ^ Objects.hashCode(ownerType) ^ Objects.hashCode(rawType); } public String toString() { StringBuilder sb = new StringBuilder(); if (ownerType != null) { if (ownerType instanceof Class) sb.append(((Class)ownerType).getName()); else sb.append(ownerType.toString()); sb.append("."); if (ownerType instanceof ParameterizedTypeImpl) { // Find simple name of nested type by removing the // shared prefix with owner. sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$", "")); } else sb.append(rawType.getName()); } else sb.append(rawType.getName()); if (actualTypeArguments != null && actualTypeArguments.length > 0) { sb.append("<"); boolean first = true; for(Type t: actualTypeArguments) { if (!first) sb.append(", "); sb.append(t.getTypeName()); first = false; } sb.append(">"); } return sb.toString(); } }