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 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.getSimpleName());
 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 }