View Javadoc
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 Type[] actualTypeArguments;
42      private Class<?>  rawType;
43      private 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 <tt>typeArgs</tt>) 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 <tt>ParameterizedType</tt>
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 <tt>Type</tt> 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 <tt>Type</tt> objects representing the actual type
106      *     arguments to this type
107      * @throws <tt>TypeNotPresentException</tt> if any of the
108      *     actual type arguments refers to a non-existent type declaration
109      * @throws <tt>MalformedParameterizedTypeException</tt> 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 <tt>Type</tt> object representing the class or interface
120      * that declared this type.
121      *
122      * @return the <tt>Type</tt> 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 <tt>Type</tt> object representing the type that this type
132      * is a member of.  For example, if this type is <tt>O<T>.I<S></tt>,
133      * return a representation of <tt>O<T></tt>.
134      *
135      * <p>If this type is a top-level type, <tt>null</tt> is returned.
136      *
137      * @return a <tt>Type</tt> object representing the type that
138      *     this type is a member of. If this type is a top-level type,
139      *     <tt>null</tt> is returned
140      * @throws <tt>TypeNotPresentException</tt> if the owner type
141      *     refers to a non-existent type declaration
142      * @throws <tt>MalformedParameterizedTypeException</tt> 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 }