blob: 0e03782213a7875d518c1ac68d3833e93ab1eea9 [file] [log] [blame]
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Tests com.sun.beans.TypeResolver
* @author Eamonn McManus
*/
import com.sun.beans.TypeResolver;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
public class TestTypeResolver {
static final List<Class<?>> failedCases = new ArrayList<Class<?>>();
public static void main(String[] args) throws Exception {
test(TestTypeResolver.class);
if (failedCases.isEmpty())
System.out.println("TEST PASSED");
else {
System.out.println("TEST FAILED: failed cases: " + failedCases);
throw new Error("TEST FAILED");
}
}
private static void test(Class<?> c) throws Exception {
/* Every public nested class represents a test. In each case, either
* the class contains further nested classes, in which case we
* call this method recursively; or it declares or inherits a
* method called getThing() and it declares a static field
* called "expect" which
* is the Type of that method's return value. The test consists
* of checking that the value returned by
* TypeResolver.resolveInClass is indeed this Type.
*/
System.out.println("Test " + c);
Class<?>[] nested = c.getClasses();
Arrays.sort(nested, classNameComparator);
for (Class<?> n : nested)
test(n);
final Method m;
try {
m = c.getMethod("getThing");
} catch (NoSuchMethodException e) {
if (nested.length == 0) {
System.out.println(
"TEST ERROR: class " + c.getName() + " has neither " +
"nested classes nor getThing() method");
failedCases.add(c);
}
return;
}
Object expect = null;
try {
Field f = c.getDeclaredField("expect");
expect = f.get(null);
} catch (NoSuchFieldException e) {
Class<?> outer = c.getDeclaringClass();
if (outer != null) {
try {
Field f = outer.getDeclaredField("expect" + c.getSimpleName());
expect = f.get(null);
} catch (NoSuchFieldException e1) {
}
}
}
if (expect == null) {
System.out.println(
"TEST ERROR: class " + c.getName() + " has getThing() method " +
"but not expect field");
failedCases.add(c);
return;
}
Type t = m.getGenericReturnType();
// t = FixType.fixType(t, c);
t = TypeResolver.resolveInClass(c, t);
System.out.print("..." + t);
// check expected value, and incidentally equals method defined
// by private implementations of the various Type interfaces
if (expect.equals(t) && t.equals(expect))
System.out.println(", as expected");
else {
System.out.println(" BUT SHOULD BE " + expect);
failedCases.add(c);
}
}
private static class ClassNameComparator implements Comparator<Class<?>> {
public int compare(Class<?> a, Class<?> b) {
return a.getName().compareTo(b.getName());
}
}
private static final Comparator<Class<?>> classNameComparator =
new ClassNameComparator();
private static abstract class TypeVariableImpl<D extends GenericDeclaration>
implements TypeVariable<D> {
private final String name;
private final D gd;
private final Type[] bounds;
TypeVariableImpl(String name, D gd, Type... bounds) {
this.name = name;
this.gd = gd;
if (bounds.length == 0)
bounds = new Type[] {Object.class};
this.bounds = bounds.clone();
}
public Type[] getBounds() {
return bounds.clone();
}
public D getGenericDeclaration() {
return gd;
}
public String getName() {
return name;
}
public String toString() {
return name;
}
public boolean equals(Object o) {
if (!(o instanceof TypeVariable))
return false;
TypeVariable tv = (TypeVariable) o;
return equal(name, tv.getName()) &&
equal(gd, tv.getGenericDeclaration()) &&
Arrays.equals(bounds, tv.getBounds());
}
public int hashCode() {
return hash(name) ^ hash(gd) ^ Arrays.hashCode(bounds);
}
}
private static class ClassTypeVariable extends TypeVariableImpl<Class<?>> {
ClassTypeVariable(String name, Class<?> gd, Type... bounds) {
super(name, gd, bounds);
}
}
private static class MethodTypeVariable extends TypeVariableImpl<Method> {
MethodTypeVariable(String name, Method gd, Type... bounds) {
super(name, gd, bounds);
}
}
private static class WildcardTypeImpl implements WildcardType {
private final Type[] upperBounds;
private final Type[] lowerBounds;
WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
if (upperBounds == null || upperBounds.length == 0)
upperBounds = new Type[] {Object.class};
if (lowerBounds == null)
lowerBounds = new Type[0];
this.upperBounds = upperBounds.clone();
this.lowerBounds = lowerBounds.clone();
}
public Type[] getUpperBounds() {
return upperBounds.clone();
}
public Type[] getLowerBounds() {
return lowerBounds.clone();
}
public boolean equals(Object o) {
if (o instanceof WildcardType) {
WildcardType wt = (WildcardType) o;
return Arrays.equals(upperBounds, wt.getUpperBounds()) &&
Arrays.equals(lowerBounds, wt.getLowerBounds());
} else
return false;
}
public int hashCode() {
return Arrays.hashCode(upperBounds) ^ Arrays.hashCode(lowerBounds);
}
public String toString() {
StringBuilder sb = new StringBuilder("?");
if (upperBounds.length > 1 || upperBounds[0] != Object.class) {
sb.append(" extends");
appendBounds(sb, upperBounds);
}
if (lowerBounds.length > 0) {
sb.append(" super");
appendBounds(sb, lowerBounds);
}
return sb.toString();
}
private static void appendBounds(StringBuilder sb, Type[] bounds) {
boolean and = false;
for (Type bound : bounds) {
if (and)
sb.append(" &");
sb.append(" ");
if (bound instanceof Class)
sb.append(((Class<?>) bound).getName());
else
sb.append(bound);
and = true;
}
}
}
static boolean equal(Object x, Object y) {
if (x == y)
return true;
if (x == null || y == null)
return false;
return x.equals(y);
}
static int hash(Object x) {
return (x == null) ? null : x.hashCode();
}
public static class Outer<T> {
public class Inner {
public T getThing() {
return null;
}
}
static final Type expectInner = new ClassTypeVariable("T", Outer.class);
}
public static class Super<T> {
static final Type expect = new ClassTypeVariable("T", Super.class);
public T getThing() {
return null;
}
}
public static class Int extends Super<Integer> {
static final Type expect = Integer.class;
}
public static class IntOverride extends Int {
static final Type expect = Integer.class;
public Integer getThing() {
return null;
}
}
public static class Mid<X> extends Super<X> {
static final Type expect = new ClassTypeVariable("X", Mid.class);
}
public static class Str extends Mid<String> {
static final Type expect = String.class;
}
public static class ListInt extends Super<List<Integer>> {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {Integer.class}, null);
}
public static class ListIntSub extends ListInt {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {Integer.class}, null);
public List<Integer> getThing() {
return null;
}
}
public static class ListU<U> extends Super<List<U>> {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {new ClassTypeVariable("U", ListU.class)}, null);
}
public static class ListUInt extends ListU<Integer> {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {Integer.class}, null);
}
public static class ListUSub<V> extends ListU<V> {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {new ClassTypeVariable("V", ListUSub.class)}, null);
public List<V> getThing() {
return null;
}
}
public static class ListUSubInt extends ListUSub<Integer> {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {Integer.class}, null);
}
public static class TwoParams<S, T> extends Super<S> {
static final Type expect = new ClassTypeVariable("S", TwoParams.class);
}
public static class TwoParamsSub<T> extends TwoParams<T, Integer> {
static final Type expect = new ClassTypeVariable("T", TwoParamsSub.class);
}
public static class TwoParamsSubSub extends TwoParamsSub<String> {
static final Type expect = String.class;
}
public static interface Intf<T> {
static final Type expect = new ClassTypeVariable("T", Intf.class);
public T getThing();
}
public static abstract class Impl implements Intf<String> {
static final Type expect = String.class;
}
public static class Impl2 extends Super<String> implements Intf<String> {
static final Type expect = String.class;
}
public static class Bound<T extends Number> extends Super<T> {
static final Type expect = new ClassTypeVariable("T", Bound.class, Number.class);
}
public static class BoundInt extends Bound<Integer> {
static final Type expect = Integer.class;
}
public static class RawBound extends Bound {
static final Type expect = Number.class;
}
public static class RawBoundInt extends BoundInt {
static final Type expect = Integer.class;
}
public static class MethodParam<T> {
private static final Method m;
static {
try {
m = MethodParam.class.getMethod("getThing");
} catch (Exception e) {
throw new AssertionError(e);
}
}
static final Type expect = new MethodTypeVariable("T", m);
public <T> T getThing() {
return null;
}
}
public static class Raw extends Super {
static final Type expect = Object.class;
}
public static class RawSub extends Raw {
static final Type expect = Object.class;
}
public static class SimpleArray extends Super<String[]> {
static final Type expect = String[].class;
}
public static class GenericArray extends Super<List<String>[]> {
static final Type expect = GenericArrayTypeImpl.make(
ParameterizedTypeImpl.make(List.class, new Type[] {String.class}, null));
}
public static class GenericArrayT<T> extends Super<T[]> {
static final Type expect = GenericArrayTypeImpl.make(
new ClassTypeVariable("T", GenericArrayT.class));
}
public static class GenericArrayTSub extends GenericArrayT<String[]> {
static final Type expect = String[][].class;
}
public static class Wildcard extends Super<List<?>> {
static final Type expect = ParameterizedTypeImpl.make(
List.class, new Type[] {new WildcardTypeImpl(null, null)}, null);
}
public static class WildcardT<T> extends Super<List<? extends T>> {
static final Type expect = ParameterizedTypeImpl.make(
List.class,
new Type[] {
new WildcardTypeImpl(
new Type[] {new ClassTypeVariable("T", WildcardT.class)},
null)},
null);
}
public static class WildcardTSub extends WildcardT<Integer> {
static final Type expect = ParameterizedTypeImpl.make(
List.class,
new Type[] {
new WildcardTypeImpl(
new Type[] {Integer.class},
null)},
null);
}
public static class WildcardTSubSub<X> extends WildcardTSub {
// X is just so we can have a raw subclass
static final Type expect = WildcardTSub.expect;
}
public static class RawWildcardTSubSub extends WildcardTSubSub {
static final Type expect = List.class;
}
public static class WildcardTSuper<T> extends Super<List<? super T>> {
static final Type expect = ParameterizedTypeImpl.make(
List.class,
new Type[] {
new WildcardTypeImpl(
null,
new Type[] {new ClassTypeVariable("T", WildcardTSuper.class)})},
null);
}
public static class WildcardTSuperSub extends WildcardTSuper<Integer> {
static final Type expect = ParameterizedTypeImpl.make(
List.class,
new Type[] {
new WildcardTypeImpl(
null,
new Type[] {Integer.class})},
null);
}
public static class SuperMap<K, V> {
static final Type expect = ParameterizedTypeImpl.make(
Map.class,
new Type[] {
new ClassTypeVariable("K", SuperMap.class),
new ClassTypeVariable("V", SuperMap.class)},
null);
public Map<K, V> getThing() {
return null;
}
}
public static class SubMap extends SuperMap<String, Integer> {
static final Type expect = ParameterizedTypeImpl.make(
Map.class,
new Type[] {String.class, Integer.class},
null);
}
public static class ListListT<T> extends Super<List<List<T>>> {
static final Type expect = ParameterizedTypeImpl.make(
List.class,
new Type[] {
ParameterizedTypeImpl.make(
List.class,
new Type[] {new ClassTypeVariable("T", ListListT.class)},
null)},
null);
}
public static class ListListString extends ListListT<String> {
static final Type expect = ParameterizedTypeImpl.make(
List.class,
new Type[] {
ParameterizedTypeImpl.make(
List.class,
new Type[] {String.class},
null)},
null);
}
public static class UExtendsT<T, U extends T> extends Super<U> {
static final Type expect = new ClassTypeVariable(
"U", UExtendsT.class, new ClassTypeVariable("T", UExtendsT.class));
}
public static class UExtendsTSub extends UExtendsT<Number, Integer> {
static final Type expect = Integer.class;
}
public static class SelfRef<T extends SelfRef<T>> extends Super<T> {
static final Type expect =
SelfRef.class.getTypeParameters()[0];
}
public static class SelfRefSub extends SelfRef<SelfRefSub> {
static final Type expect = SelfRefSub.class;
}
}