001package net.gdface.utils;
002import static com.google.common.base.Preconditions.*;
003
004import java.lang.reflect.MalformedParameterizedTypeException;
005import java.lang.reflect.ParameterizedType;
006import java.lang.reflect.Type;
007import java.lang.reflect.TypeVariable;
008import java.util.Arrays;
009
010import com.google.common.base.Function;
011import com.google.common.collect.Lists;
012import com.google.common.reflect.TypeToken;
013
014/**
015 * 基于jdk1.7中 {@link sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl}实现<br>
016 * 修正原版本中toString方法错误
017 * @author guyadong
018 *
019 */
020@SuppressWarnings("restriction")
021public class ParameterizedTypeImpl implements ParameterizedType {
022        private Type[] actualTypeArguments;
023        private Class<?> rawType;
024        private Type ownerType;
025        public static final Function<Type,Type> WRAPPER = new Function<Type,Type>(){
026
027                @Override
028                public Type apply(Type input) {
029                        if(input instanceof ParameterizedTypeImpl){
030                                return input;
031                        }else if(input instanceof ParameterizedType){
032                                return new ParameterizedTypeImpl((ParameterizedType)input);
033                        }
034                        return input;
035                }};
036        /**
037         * 构造方法
038         * 基于已有{@link ParameterizedType}实例构造一个新对象
039         * @param source 不可为{@link null}
040         */
041        public ParameterizedTypeImpl(ParameterizedType source){
042                this(TypeToken.of(checkNotNull(source)).getRawType(),source.getActualTypeArguments(),source.getOwnerType());
043        }
044        public ParameterizedTypeImpl(Class<?> rawType, Type[] actualTypeArguments, Type ownerType) {
045                checkArgument(null !=rawType && null !=actualTypeArguments);
046                this.actualTypeArguments = Lists.transform(Lists.newArrayList(actualTypeArguments),WRAPPER).toArray(new Type[0]);
047                this.rawType = rawType;
048                this.ownerType = WRAPPER.apply(ownerType != null ? ownerType : rawType.getDeclaringClass());
049                this.validateConstructorArguments();
050        }
051
052        private void validateConstructorArguments() {
053                TypeVariable<?>[] formals = this.rawType.getTypeParameters();
054                if (formals.length != this.actualTypeArguments.length) {
055                        throw new MalformedParameterizedTypeException();
056                }
057                for (int i = 0; i < this.actualTypeArguments.length; ++i) {
058                }
059        }
060
061        @Override
062        public Type[] getActualTypeArguments() {
063                return (Type[]) this.actualTypeArguments.clone();
064        }
065
066        @Override
067        public Class<?> getRawType() {
068                return this.rawType;
069        }
070
071        @Override
072        public Type getOwnerType() {
073                return this.ownerType;
074        }
075
076        @Override
077        public boolean equals(Object o) {
078                if (o instanceof ParameterizedType) {
079                        ParameterizedType that = (ParameterizedType) o;
080                        if (this == that) {
081                                return true;
082                        }
083                        Type thatOwner = that.getOwnerType();
084                        Type thatRawType = that.getRawType();
085                        return (this.ownerType == null ? thatOwner == null : this.ownerType.equals(thatOwner))
086                                        && (this.rawType == null ? thatRawType == null : this.rawType.equals(thatRawType))
087                                        && Arrays.equals(this.actualTypeArguments, that.getActualTypeArguments());
088                }
089                return false;
090        }
091
092        public int hashCode() {
093                return Arrays.hashCode(this.actualTypeArguments) ^ (this.ownerType == null ? 0 : this.ownerType.hashCode())
094                                ^ (this.rawType == null ? 0 : this.rawType.hashCode());
095        }
096
097        public String toString() {
098                StringBuilder sb = new StringBuilder();
099                if (this.ownerType != null) {
100                        if (this.ownerType instanceof Class) {
101                                sb.append(((Class<?>) this.ownerType).getName());
102                        } else {
103                                sb.append(this.ownerType.toString());
104                        }
105                        sb.append(".");
106                        if (this.ownerType instanceof ParameterizedTypeImpl) {
107                                sb.append(this.rawType.getName()
108                                                .replace(((ParameterizedTypeImpl) this.ownerType).rawType.getName() + "$", ""));
109                        } else {
110                                sb.append(this.rawType.getSimpleName());
111                        }
112                } else {
113                        sb.append(this.rawType.getName());
114                }
115                if (this.actualTypeArguments != null && this.actualTypeArguments.length > 0) {
116                        sb.append("<");
117                        boolean first = true;
118                        for (Type t : this.actualTypeArguments) {
119                                if (!first) {
120                                        sb.append(", ");
121                                }
122                                if (t instanceof Class) {
123                                        sb.append(((Class<?>) t).getName());
124                                } else {
125                                        sb.append(t.toString());
126                                }
127                                first = false;
128                        }
129                        sb.append(">");
130                }
131                return sb.toString();
132        }
133        /**
134         * 将当前对象的类型参数中为{@code oldType}的元素替换为{@code newType}
135         * @param oldType 不可为{@code null}
136         * @param newType 不可为{@code null}
137         * @return
138         */
139        public ParameterizedType transform(Type oldType,Type newType ){         
140                checkNotNull(oldType);
141                checkNotNull(newType);
142                Type[] typeArgs = getActualTypeArguments();
143                for(int i =0 ;i<typeArgs.length;++i){
144                        if(typeArgs[i]==oldType)
145                                typeArgs[i] = newType;
146                }
147                return new ParameterizedTypeImpl(TypeToken.of(this).getRawType(), typeArgs, getOwnerType());
148        }
149        /**
150         * 用指定的类型参数替换当前对象的类型参数<br>
151         * 新参数的个数与当前对象的类型参数个数必须一致,
152         * 如果新参数数组中元素为{@code null}则对应的参数不会被替换
153         * @param newTypeArguments
154         * @return
155         */
156        public ParameterizedType transform(Type[] newTypeArguments){
157                checkNotNull(newTypeArguments);
158                Type[] typeArgs = getActualTypeArguments();
159                checkArgument(newTypeArguments.length == typeArgs.length );
160                for(int i=0;i<typeArgs.length;++i){
161                        if(null != newTypeArguments[i]){
162                                typeArgs[i] = newTypeArguments[i];
163                        }
164                }
165                return new ParameterizedTypeImpl(TypeToken.of(this).getRawType(), typeArgs, getOwnerType());
166        }
167}