001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj.util;
032
033import java.lang.reflect.ParameterizedType;
034import java.lang.reflect.Type;
035
036/**
037 * Default implementation of {@link java.lang.reflect.ParameterizedType}
038 *
039 * @author Olivier
040 */
041public class DefaultParameterizedType implements ParameterizedType {
042
043    private final Type[] actualTypeArguments;
044    private final Type ownerType;
045    private final Type rawType;
046
047    public DefaultParameterizedType(Type ownerType, Type rawType, Type[] actualTypeArguments) {
048        this.ownerType = ownerType;
049        this.actualTypeArguments = actualTypeArguments;
050        this.rawType = rawType;
051    }
052
053    public DefaultParameterizedType(Type rawType, Type... actualTypeArguments) {
054        this(null, rawType, actualTypeArguments);
055    }
056
057    @Override
058    public String toString() {
059        StringBuilder b = new StringBuilder();
060        if (ownerType != null) {
061            b.append(Utils.toString(ownerType)).append(".");
062        }
063        b.append(rawType);
064        if (actualTypeArguments.length > 0) {
065            b.append("<");
066            for (int i = 0; i < actualTypeArguments.length; i++) {
067                if (i > 0) {
068                    b.append(", ");
069                }
070                b.append(Utils.toString(actualTypeArguments[i]));
071            }
072            b.append(">");
073        }
074        return b.toString();
075    }
076
077    /**
078     * Builds a parameterized type with the provided raw type and type
079     * arguments.<br>
080     * For instance,
081     * <code>paramType(Pointer.class, Integer.class)</code> gives you the type
082     * of
083     * <code>Pointer&lt;Integer&gt;</code>.
084     */
085    public static Type paramType(Type rawType, Type... actualTypeArguments) {
086        return new DefaultParameterizedType(rawType, actualTypeArguments);
087    }
088
089    //@Override
090    public Type[] getActualTypeArguments() {
091        return actualTypeArguments.clone();
092    }
093
094    //@Override
095    public java.lang.reflect.Type getOwnerType() {
096        return ownerType;
097    }
098
099    //@Override
100    public java.lang.reflect.Type getRawType() {
101        return rawType;
102    }
103
104    //@Override
105    public int hashCode() {
106        int h = getRawType().hashCode();
107        if (getOwnerType() != null) {
108            h ^= getOwnerType().hashCode();
109        }
110        for (int i = 0, n = actualTypeArguments.length; i < n; i++) {
111            Type arg = actualTypeArguments[i];
112            if (arg != null) {
113                h ^= arg.hashCode();
114            }
115        }
116        return h;
117    }
118
119    static boolean eq(Object a, Object b) {
120        if ((a == null) != (b == null)) {
121            return false;
122        }
123        if (a != null && !a.equals(b)) {
124            return false;
125        }
126        return true;
127    }
128    //@Override
129
130    public boolean equals(Object o) {
131        if (o == null || !(o instanceof DefaultParameterizedType)) {
132            return false;
133        }
134
135        DefaultParameterizedType t = (DefaultParameterizedType) o;
136        if (!eq(getRawType(), t.getRawType())) {
137            return false;
138        }
139        if (!eq(getOwnerType(), t.getOwnerType())) {
140            return false;
141        }
142
143        Object[] tp = t.actualTypeArguments;
144        if (actualTypeArguments.length != tp.length) {
145            return false;
146        }
147
148        for (int i = 0, n = actualTypeArguments.length; i < n; i++) {
149            if (!eq(actualTypeArguments[i], tp[i])) {
150                return false;
151            }
152        }
153
154        return true;
155    }
156}