1 /*
   2  * Copyright (c) 2003, 2013, 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.Objects;
  37 
  38 /** Implementing class for ParameterizedType interface. */
  39 
  40 public class ParameterizedTypeImpl implements ParameterizedType {
  41     private final Type[] actualTypeArguments;
  42     private final Class<?>  rawType;
  43     private final Type   ownerType;
  44 
  45     private ParameterizedTypeImpl(Class<?> rawType,
  46                                   Type[] actualTypeArguments,
  47                                   Type ownerType) {
  48         this.actualTypeArguments = actualTypeArguments;
  49         this.rawType             = rawType;
  50         this.ownerType = (ownerType != null) ? ownerType : rawType.getDeclaringClass();
  51         validateConstructorArguments();
  52     }
  53 
  54     private void validateConstructorArguments() {
  55         TypeVariable<?>[] formals = rawType.getTypeParameters();
  56         // check correct arity of actual type args
  57         if (formals.length != actualTypeArguments.length){
  58             throw new MalformedParameterizedTypeException();
  59         }
  60         for (int i = 0; i < actualTypeArguments.length; i++) {
  61             // check actuals against formals' bounds
  62         }
  63     }
  64 
  65     /**
  66      * Static factory. Given a (generic) class, actual type arguments
  67      * and an owner type, creates a parameterized type.
  68      * This class can be instantiated with a a raw type that does not
  69      * represent a generic type, provided the list of actual type
  70      * arguments is empty.
  71      * If the ownerType argument is null, the declaring class of the
  72      * raw type is used as the owner type.
  73      * <p> This method throws a MalformedParameterizedTypeException
  74      * under the following circumstances:
  75      * If the number of actual type arguments (i.e., the size of the
  76      * array {@code typeArgs}) does not correspond to the number of
  77      * formal type arguments.
  78      * If any of the actual type arguments is not an instance of the
  79      * bounds on the corresponding formal.
  80      * @param rawType the Class representing the generic type declaration being
  81      * instantiated
  82      * @param actualTypeArguments a (possibly empty) array of types
  83      * representing the actual type arguments to the parameterized type
  84      * @param ownerType the enclosing type, if known.
  85      * @return An instance of {@code ParameterizedType}
  86      * @throws MalformedParameterizedTypeException if the instantiation
  87      * is invalid
  88      */
  89     public static ParameterizedTypeImpl make(Class<?> rawType,
  90                                              Type[] actualTypeArguments,
  91                                              Type ownerType) {
  92         return new ParameterizedTypeImpl(rawType, actualTypeArguments,
  93                                          ownerType);
  94     }
  95 
  96 
  97     /**
  98      * Returns an array of {@code Type} objects representing the actual type
  99      * arguments to this type.
 100      *
 101      * <p>Note that in some cases, the returned array be empty. This can occur
 102      * if this type represents a non-parameterized type nested within
 103      * a parameterized type.
 104      *
 105      * @return an array of {@code Type} objects representing the actual type
 106      *     arguments to this type
 107      * @throws TypeNotPresentException if any of the
 108      *     actual type arguments refers to a non-existent type declaration
 109      * @throws MalformedParameterizedTypeException if any of the
 110      *     actual type parameters refer to a parameterized type that cannot
 111      *     be instantiated for any reason
 112      * @since 1.5
 113      */
 114     public Type[] getActualTypeArguments() {
 115         return actualTypeArguments.clone();
 116     }
 117 
 118     /**
 119      * Returns the {@code Type} object representing the class or interface
 120      * that declared this type.
 121      *
 122      * @return the {@code Type} object representing the class or interface
 123      *     that declared this type
 124      */
 125     public Class<?> getRawType() {
 126         return rawType;
 127     }
 128 
 129 
 130     /**
 131      * Returns a {@code Type} object representing the type that this type
 132      * is a member of.  For example, if this type is {@code O<T>.I<S>},
 133      * return a representation of {@code O<T>}.
 134      *
 135      * <p>If this type is a top-level type, {@code null} is returned.
 136      *
 137      * @return a {@code Type} object representing the type that
 138      *     this type is a member of. If this type is a top-level type,
 139      *     {@code null} is returned
 140      * @throws TypeNotPresentException if the owner type
 141      *     refers to a non-existent type declaration
 142      * @throws MalformedParameterizedTypeException if the owner type
 143      *     refers to a parameterized type that cannot be instantiated
 144      *     for any reason
 145      *
 146      */
 147     public Type getOwnerType() {
 148         return ownerType;
 149     }
 150 
 151     /*
 152      * From the JavaDoc for java.lang.reflect.ParameterizedType
 153      * "Instances of classes that implement this interface must
 154      * implement an equals() method that equates any two instances
 155      * that share the same generic type declaration and have equal
 156      * type parameters."
 157      */
 158     @Override
 159     public boolean equals(Object o) {
 160         if (o instanceof ParameterizedType) {
 161             // Check that information is equivalent
 162             ParameterizedType that = (ParameterizedType) o;
 163 
 164             if (this == that)
 165                 return true;
 166 
 167             Type thatOwner   = that.getOwnerType();
 168             Type thatRawType = that.getRawType();
 169 
 170             if (false) { // Debugging
 171                 boolean ownerEquality = (ownerType == null ?
 172                                          thatOwner == null :
 173                                          ownerType.equals(thatOwner));
 174                 boolean rawEquality = (rawType == null ?
 175                                        thatRawType == null :
 176                                        rawType.equals(thatRawType));
 177 
 178                 boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone
 179                                                         that.getActualTypeArguments());
 180                 for (Type t : actualTypeArguments) {
 181                     System.out.printf("\t\t%s%s%n", t, t.getClass());
 182                 }
 183 
 184                 System.out.printf("\towner %s\traw %s\ttypeArg %s%n",
 185                                   ownerEquality, rawEquality, typeArgEquality);
 186                 return ownerEquality && rawEquality && typeArgEquality;
 187             }
 188 
 189             return
 190                 Objects.equals(ownerType, thatOwner) &&
 191                 Objects.equals(rawType, thatRawType) &&
 192                 Arrays.equals(actualTypeArguments, // avoid clone
 193                               that.getActualTypeArguments());
 194         } else
 195             return false;
 196     }
 197 
 198     @Override
 199     public int hashCode() {
 200         return
 201             Arrays.hashCode(actualTypeArguments) ^
 202             Objects.hashCode(ownerType) ^
 203             Objects.hashCode(rawType);
 204     }
 205 
 206     public String toString() {
 207         StringBuilder sb = new StringBuilder();
 208 
 209         if (ownerType != null) {
 210             if (ownerType instanceof Class)
 211                 sb.append(((Class)ownerType).getName());
 212             else
 213                 sb.append(ownerType.toString());
 214 
 215             sb.append(".");
 216 
 217             if (ownerType instanceof ParameterizedTypeImpl) {
 218                 // Find simple name of nested type by removing the
 219                 // shared prefix with owner.
 220                 sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$",
 221                                          ""));
 222             } else
 223                 sb.append(rawType.getName());
 224         } else
 225             sb.append(rawType.getName());
 226 
 227         if (actualTypeArguments != null &&
 228             actualTypeArguments.length > 0) {
 229             sb.append("<");
 230             boolean first = true;
 231             for(Type t: actualTypeArguments) {
 232                 if (!first)
 233                     sb.append(", ");
 234                 sb.append(t.getTypeName());
 235                 first = false;
 236             }
 237             sb.append(">");
 238         }
 239 
 240         return sb.toString();
 241     }
 242 }