1 /*
   2  * Copyright (c) 1997, 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 com.sun.xml.internal.bind.v2.model.nav;
  27 
  28 import java.lang.reflect.MalformedParameterizedTypeException;
  29 import java.lang.reflect.ParameterizedType;
  30 import java.lang.reflect.Type;
  31 import java.lang.reflect.TypeVariable;
  32 import java.util.Arrays;
  33 
  34 
  35 /**
  36  * {@link ParameterizedType} implementation.
  37  */
  38 class ParameterizedTypeImpl implements ParameterizedType {
  39     private Type[] actualTypeArguments;
  40     private Class<?> rawType;
  41     private Type ownerType;
  42 
  43     ParameterizedTypeImpl(Class<?> rawType,
  44                                   Type[] actualTypeArguments,
  45                                   Type ownerType) {
  46         this.actualTypeArguments = actualTypeArguments;
  47         this.rawType = rawType;
  48         if (ownerType != null) {
  49             this.ownerType = ownerType;
  50         } else {
  51             this.ownerType = rawType.getDeclaringClass();
  52         }
  53         validateConstructorArguments();
  54     }
  55 
  56     private void validateConstructorArguments() {
  57         TypeVariable/*<?>*/[] formals = rawType.getTypeParameters();
  58         // check correct arity of actual type args
  59         if (formals.length != actualTypeArguments.length) {
  60             throw new MalformedParameterizedTypeException();
  61         }
  62 /*
  63         for (int i = 0; i < actualTypeArguments.length; i++) {
  64             // check actuals against formals' bounds
  65         }
  66 */
  67     }
  68 
  69     public Type[] getActualTypeArguments() {
  70         return actualTypeArguments.clone();
  71     }
  72 
  73     public Class<?> getRawType() {
  74         return rawType;
  75     }
  76 
  77     public Type getOwnerType() {
  78         return ownerType;
  79     }
  80 
  81     /*
  82      * From the JavaDoc for java.lang.reflect.ParameterizedType
  83      * "Instances of classes that implement this interface must
  84      * implement an equals() method that equates any two instances
  85      * that share the same generic type declaration and have equal
  86      * type parameters."
  87      */
  88     @Override
  89     public boolean equals(Object o) {
  90         if (o instanceof ParameterizedType) {
  91             // Check that information is equivalent
  92             ParameterizedType that = (ParameterizedType) o;
  93 
  94             if (this == that)
  95                 return true;
  96 
  97             Type thatOwner = that.getOwnerType();
  98             Type thatRawType = that.getRawType();
  99 
 100 /*
 101             if (false) { // Debugging
 102                 boolean ownerEquality = (ownerType == null ?
 103                         thatOwner == null :
 104                         ownerType.equals(thatOwner));
 105                 boolean rawEquality = (rawType == null ?
 106                         thatRawType == null :
 107                         rawType.equals(thatRawType));
 108 
 109                 boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone
 110                         that.getActualTypeArguments());
 111                 for (Type t : actualTypeArguments) {
 112                     System.out.printf("\t\t%s%s%n", t, t.getClass());
 113                 }
 114 
 115                 System.out.printf("\towner %s\traw %s\ttypeArg %s%n",
 116                         ownerEquality, rawEquality, typeArgEquality);
 117                 return ownerEquality && rawEquality && typeArgEquality;
 118             }
 119 */
 120 
 121 
 122             return
 123                     (ownerType == null ?
 124                     thatOwner == null :
 125                     ownerType.equals(thatOwner)) &&
 126                     (rawType == null ?
 127                     thatRawType == null :
 128                     rawType.equals(thatRawType)) &&
 129                     Arrays.equals(actualTypeArguments, // avoid clone
 130                             that.getActualTypeArguments());
 131         } else
 132             return false;
 133     }
 134 
 135     @Override
 136     public int hashCode() {
 137         return  Arrays.hashCode(actualTypeArguments) ^
 138                 (ownerType == null ? 0 : ownerType.hashCode()) ^
 139                 (rawType == null ? 0 : rawType.hashCode());
 140     }
 141 
 142     public String toString() {
 143         StringBuilder sb = new StringBuilder();
 144 
 145         if (ownerType != null) {
 146             if (ownerType instanceof Class)
 147                 sb.append(((Class) ownerType).getName());
 148             else
 149                 sb.append(ownerType.toString());
 150 
 151             sb.append(".");
 152 
 153             if (ownerType instanceof ParameterizedTypeImpl) {
 154                 // Find simple name of nested type by removing the
 155                 // shared prefix with owner.
 156                 sb.append(rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$",
 157                         ""));
 158             } else
 159                 sb.append(rawType.getName());
 160         } else
 161             sb.append(rawType.getName());
 162 
 163         if (actualTypeArguments != null &&
 164                 actualTypeArguments.length > 0) {
 165             sb.append("<");
 166             boolean first = true;
 167             for (Type t : actualTypeArguments) {
 168                 if (!first)
 169                     sb.append(", ");
 170                 if (t instanceof Class)
 171                     sb.append(((Class) t).getName());
 172                 else
 173                     sb.append(t.toString());
 174                 first = false;
 175             }
 176             sb.append(">");
 177         }
 178 
 179         return sb.toString();
 180     }
 181 }