/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.classinfo.test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.jboss.reflect.plugins.AnnotationInfoImpl;
import org.jboss.reflect.plugins.AnnotationValueImpl;
import org.jboss.reflect.plugins.ConstructorInfoImpl;
import org.jboss.reflect.plugins.FieldInfoImpl;
import org.jboss.reflect.plugins.MethodInfoImpl;
import org.jboss.reflect.spi.AnnotationValue;
import org.jboss.reflect.spi.ClassInfo;
import org.jboss.reflect.spi.ConstructorInfo;
import org.jboss.reflect.spi.FieldInfo;
import org.jboss.reflect.spi.InterfaceInfo;
import org.jboss.reflect.spi.MethodInfo;
import org.jboss.reflect.spi.PackageInfo;
import org.jboss.reflect.spi.ParameterInfo;
import org.jboss.reflect.spi.TypeInfo;
import org.jboss.reflect.spi.TypeInfoFactory;
import org.jboss.reflect.spi.Value;
import org.jboss.test.ContainerTest;
/**
* AbstractClassInfoTest.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 1.1 $
*/
public abstract class AbstractClassInfoTest extends ContainerTest
{
public AbstractClassInfoTest(String name)
{
super(name);
}
@SuppressWarnings("deprecation")
protected TypeInfo testBasics(Class<?> clazz, TypeInfo expected) throws Throwable
{
TypeInfoFactory factory = getTypeInfoFactory();
getLog().debug("Using typeInfoFactory: " + factory);
TypeInfo info = factory.getTypeInfo(clazz.getName(), getClass().getClassLoader());
getLog().debug("Got: " + info + " from " + clazz);
assertNotNull(info);
assertEquals(info, expected);
ClassLoader cl = getClass().getClassLoader();
info = factory.getTypeInfo(clazz);
getLog().debug("Got: " + info + " from " + clazz.getName() + " cl=" + cl);
assertNotNull(info);
assertEquals(info, expected);
getLog().debug("Name: " + info.getName());
assertEquals(clazz.getName(), info.getName());
getLog().debug("Type: " + info.getType());
assertEquals(clazz, info.getType());
// TODO JBMICROCONT-128 fix the serialization
if (isJavassistTestCase() == false)
{
byte[] bytes = serialize(info);
Object deserialized = deserialize(bytes);
assertTrue("Not the same object: " + info + " != " + deserialized, info == deserialized);
}
return info;
}
protected boolean isJavassistTestCase()
{
return (getClass().getName().contains("Javassist"));
}
@SuppressWarnings("deprecation")
protected void testArray(Class<?> clazz, TypeInfo info) throws Throwable
{
TypeInfo arrayType = info.getArrayType();
getLog().debug("ArrayType(0): " + arrayType);
assertTrue(arrayType.isArray());
Class<?> arrayClass = Array.newInstance(clazz, 0).getClass();
assertEquals(arrayClass, arrayType.getType());
arrayType = info.getArrayType();
getLog().debug("ArrayType(0): " + arrayType);
assertTrue(arrayType.isArray());
arrayClass = Array.newInstance(clazz, 0).getClass();
assertEquals(arrayClass, arrayType.getType());
}
protected <T> void testValues(Class<T> clazz, TypeInfo info, String[] values, T[] types) throws Throwable
{
int i = 0;
for (String value : values)
{
Object result = info.convertValue(value);
getLog().debug("Converted: " + value + " to " + result);
assertEquals(result, types[i++]);
}
}
protected void assertClassInfo(ClassInfo classInfo, Class<?> clazz) throws Throwable
{
assertEquals(clazz.isInterface(), classInfo.isInterface());
assertInterfaces(clazz, classInfo);
assertDeclaredMethods(clazz, classInfo);
assertDeclaredFields(clazz, classInfo);
assertDeclaredConstructors(clazz, classInfo);
assertSuperClass(clazz, classInfo);
assertModifiers(clazz, classInfo);
assertPackage(clazz, classInfo);
assertAnnotations(clazz, classInfo);
testArray(clazz, classInfo);
}
protected void assertModifiers(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
int expected = clazz.getModifiers();
int actual = classInfo.getModifiers();
getLog().debug(clazz + " modifier expected=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertPackage(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
Package pkg = clazz.getPackage();
PackageInfo packageInfo = classInfo.getPackage();
getLog().debug(clazz + " package=" + pkg + " packageInfo=" + packageInfo);
if (pkg == null)
{
assertNullPackageInfo(packageInfo);
return;
}
assertNotNull(packageInfo);
String expected = pkg.getName();
String actual = packageInfo.getName();
getLog().debug(clazz + " package expected=" + expected + " actual=" + actual);
assertEquals(expected, actual);
assertPackageAnnotations(pkg, packageInfo);
}
protected void assertNullPackageInfo(PackageInfo packageInfo)
{
assertNull(packageInfo);
}
protected void assertSuperClass(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
TypeInfoFactory factory = getTypeInfoFactory();
Class<?> superClass = clazz.getSuperclass();
TypeInfo superType = classInfo.getSuperclass();
getLog().debug(clazz + " superClass: " + superClass + " superType=" + superType);
if (superClass == null)
{
assertNull(classInfo.getSuperclass());
return;
}
TypeInfo expected = factory.getTypeInfo(clazz.getSuperclass());
TypeInfo actual = classInfo.getSuperclass();
assertEquals(expected, actual);
}
protected void assertInterfaces(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
TypeInfoFactory factory = getTypeInfoFactory();
Set<TypeInfo> expected = new HashSet<TypeInfo>();
for (Class<?> c : clazz.getInterfaces())
{
TypeInfo type = factory.getTypeInfo(c);
expected.add(type);
}
InterfaceInfo[] interfaces = classInfo.getInterfaces();
if (expected.isEmpty())
{
assertEmpty(interfaces);
return;
}
assertNotNull(interfaces);
assertEquals(expected.size(), interfaces.length);
Set<TypeInfo> actual = new HashSet<TypeInfo>();
for (TypeInfo intf : interfaces)
actual.add(intf);
getLog().debug(clazz + " expected interfaces=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertDeclaredFields(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
TypeInfoFactory factory = getTypeInfoFactory();
Set<FieldInfo> expected = new HashSet<FieldInfo>();
for (Field field : clazz.getDeclaredFields())
{
TypeInfo type = factory.getTypeInfo(field.getGenericType());
FieldInfo f = new FieldInfoImpl(null, field.getName(), type, field.getModifiers(), classInfo);
expected.add(f);
}
FieldInfo[] result = classInfo.getDeclaredFields();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<FieldInfo> actual = new HashSet<FieldInfo>();
for (FieldInfo f : result)
actual.add(f);
getLog().debug(clazz + " expected fields=" + expected + " actual=" + actual);
assertEquals(expected, actual);
for (Field field : clazz.getDeclaredFields())
assertDeclaredField(clazz, field, classInfo);
}
protected void assertDeclaredField(Class<?> clazz, Field field, ClassInfo classInfo) throws Throwable
{
getLog().debug("Checking field " + field.getName());
TypeInfoFactory factory = getTypeInfoFactory();
FieldInfo fieldInfo = classInfo.getDeclaredField(field.getName());
assertNotNull(field.getName(), fieldInfo);
TypeInfo type = factory.getTypeInfo(field.getGenericType());
assertTypeEquals(field.getName(), type, fieldInfo.getType());
assertEquals(classInfo, fieldInfo.getDeclaringClass());
assertEquals(field.getModifiers(), fieldInfo.getModifiers());
assertFieldAnnotations(field, fieldInfo);
}
protected void assertDeclaredMethods(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
TypeInfoFactory factory = getTypeInfoFactory();
Set<MethodInfo> expected = new HashSet<MethodInfo>();
for (Method method : clazz.getDeclaredMethods())
{
TypeInfo returnType = factory.getTypeInfo(method.getReturnType());
Class<?>[] paramClasses = method.getParameterTypes();
TypeInfo[] paramTypes = new TypeInfo[paramClasses.length];
AnnotationValue[][] paramAnnotations = new AnnotationValue[paramClasses.length][0];
int i = 0;
for (Class<?> c : paramClasses)
paramTypes[i++] = factory.getTypeInfo(c);
MethodInfo m = new MethodInfoImpl(null, method.getName(), returnType, paramTypes, paramAnnotations, null, method.getModifiers(), classInfo);
expected.add(m);
}
MethodInfo[] result = classInfo.getDeclaredMethods();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<MethodInfo> actual = new HashSet<MethodInfo>();
for (MethodInfo f : result)
actual.add(f);
getLog().debug(clazz + " expected methods=" + expected + " actual=" + actual);
assertEquals(expected, actual);
for (Method method : clazz.getDeclaredMethods())
assertDeclaredMethod(clazz, method, classInfo);
}
protected void assertDeclaredMethod(Class<?> clazz, Method method, ClassInfo classInfo) throws Throwable
{
getLog().debug("Checking method " + method.getName() + Arrays.asList(method.getParameterTypes()));
TypeInfoFactory factory = getTypeInfoFactory();
Type[] paramClasses = method.getGenericParameterTypes();
TypeInfo[] paramTypes = new TypeInfo[paramClasses.length];
for (int i = 0; i < paramClasses.length; ++i)
paramTypes[i] = factory.getTypeInfo(paramClasses[i]);
MethodInfo methodInfo = classInfo.getDeclaredMethod(method.getName(), paramTypes);
assertNotNull(method.getName(), methodInfo);
TypeInfo returnType = factory.getTypeInfo(method.getGenericReturnType());
TypeInfo[] actualParamTypes = methodInfo.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i)
assertTypeEquals(method.getName() + " param" + i, paramTypes[i], actualParamTypes[i]);
Class<?>[] exceptionClasses = method.getExceptionTypes();
TypeInfo[] expectedExceptionTypes = new TypeInfo[exceptionClasses.length];
for (int i = 0; i < exceptionClasses.length; ++i)
expectedExceptionTypes[i] = factory.getTypeInfo(exceptionClasses[i]);
TypeInfo[] actualExceptionTypes = methodInfo.getExceptionTypes();
for (int i = 0; i < exceptionClasses.length; ++i)
assertTypeEquals(method.getName() + " exception" + i, expectedExceptionTypes[i], actualExceptionTypes[i]);
assertTypeEquals(method.getName() + " returnType", returnType, methodInfo.getReturnType());
assertEquals(classInfo, methodInfo.getDeclaringClass());
assertEquals(method.getModifiers(), methodInfo.getModifiers());
assertMethodAnnotations(method, methodInfo);
assertParameterAnnotations(method, methodInfo);
}
protected void assertDeclaredConstructors(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
TypeInfoFactory factory = getTypeInfoFactory();
Set<ConstructorInfo> expected = new HashSet<ConstructorInfo>();
for (Constructor<?> constructor : clazz.getDeclaredConstructors())
{
Class<?>[] paramClasses = constructor.getParameterTypes();
TypeInfo[] paramTypes = new TypeInfo[paramClasses.length];
AnnotationValue[][] paramAnnotations = new AnnotationValue[paramClasses.length][0];
int i = 0;
for (Class<?> c : paramClasses)
paramTypes[i++] = factory.getTypeInfo(c);
ConstructorInfo c = new ConstructorInfoImpl(null, paramTypes, paramAnnotations, null, constructor.getModifiers(), classInfo);
expected.add(c);
}
ConstructorInfo[] result = classInfo.getDeclaredConstructors();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<ConstructorInfo> actual = new HashSet<ConstructorInfo>();
for (ConstructorInfo f : result)
actual.add(f);
getLog().debug(clazz + " expected constructors=" + expected + " actual=" + actual);
assertEquals(expected, actual);
for (Constructor<?> constructor : clazz.getDeclaredConstructors())
assertDeclaredConstructor(clazz, constructor, classInfo);
}
protected void assertDeclaredConstructor(Class<?> clazz, Constructor<?> constructor, ClassInfo classInfo) throws Throwable
{
getLog().debug("Checking constructor " + Arrays.asList(constructor.getParameterTypes()));
TypeInfoFactory factory = getTypeInfoFactory();
Type[] paramClasses = constructor.getGenericParameterTypes();
// HACK: This is to workaround a bug in Sun's compiler related to enum constructors
// having no generic parameters?
Type[] parameterTypes = constructor.getParameterTypes();
if (paramClasses.length != parameterTypes.length)
paramClasses = parameterTypes;
TypeInfo[] paramTypes = new TypeInfo[paramClasses.length];
for (int i = 0; i < paramClasses.length; ++i)
paramTypes[i] = factory.getTypeInfo(paramClasses[i]);
ConstructorInfo constructorInfo = classInfo.getDeclaredConstructor(paramTypes);
assertNotNull(constructorInfo);
TypeInfo[] actualParamTypes = constructorInfo.getParameterTypes();
for (int i = 0; i < paramTypes.length; ++i)
assertTypeEquals(clazz + " constructorParameter" + i, paramTypes[i], actualParamTypes[i]);
Class<?>[] exceptionClasses = constructor.getExceptionTypes();
TypeInfo[] expectedExceptionTypes = new TypeInfo[exceptionClasses.length];
for (int i = 0; i < exceptionClasses.length; ++i)
expectedExceptionTypes[i] = factory.getTypeInfo(exceptionClasses[i]);
TypeInfo[] actualExceptionTypes = constructorInfo.getExceptionTypes();
for (int i = 0; i < exceptionClasses.length; ++i)
assertTypeEquals(clazz + " constructorException" + i, expectedExceptionTypes[i], actualExceptionTypes[i]);
assertEquals(classInfo, constructorInfo.getDeclaringClass());
assertEquals(constructor.getModifiers(), constructorInfo.getModifiers());
assertConstructorAnnotations(constructor, constructorInfo);
assertParameterAnnotations(constructor, constructorInfo);
}
protected void assertAnnotations(Class<?> clazz, ClassInfo classInfo) throws Throwable
{
Set<AnnotationValue> expected = getExpectedAnnotations(clazz.getDeclaredAnnotations());
AnnotationValue[] result = classInfo.getAnnotations();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<AnnotationValue> actual = new HashSet<AnnotationValue>();
for (AnnotationValue f : result)
actual.add(f);
getLog().debug(clazz + " expected annotations=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertFieldAnnotations(Field field, FieldInfo fieldInfo) throws Throwable
{
Set<AnnotationValue> expected = getExpectedAnnotations(field.getDeclaredAnnotations());
AnnotationValue[] result = fieldInfo.getAnnotations();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<AnnotationValue> actual = new HashSet<AnnotationValue>();
for (AnnotationValue f : result)
actual.add(f);
getLog().debug(field.getName() + " expected annotations=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertMethodAnnotations(Method method, MethodInfo methodInfo) throws Throwable
{
Set<AnnotationValue> expected = getExpectedAnnotations(method.getDeclaredAnnotations());
AnnotationValue[] result = methodInfo.getAnnotations();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<AnnotationValue> actual = new HashSet<AnnotationValue>();
for (AnnotationValue f : result)
actual.add(f);
getLog().debug(method.getName() + " expected annotations=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertParameterAnnotations(Method method, MethodInfo methodInfo) throws Throwable
{
Annotation[][] annotations = method.getParameterAnnotations();
ParameterInfo[] parameters = methodInfo.getParameters();
for (int i = 0; i < annotations.length; ++i)
assertParameterAnnotations(annotations[i], parameters[i]);
}
protected void assertConstructorAnnotations(Constructor<?> constructor, ConstructorInfo constructorInfo) throws Throwable
{
Set<AnnotationValue> expected = getExpectedAnnotations(constructor.getDeclaredAnnotations());
AnnotationValue[] result = constructorInfo.getAnnotations();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<AnnotationValue> actual = new HashSet<AnnotationValue>();
for (AnnotationValue f : result)
actual.add(f);
getLog().debug("Expected annotations=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertPackageAnnotations(Package pkg, PackageInfo packageInfo) throws Throwable
{
Set<AnnotationValue> expected = getExpectedAnnotations(pkg.getDeclaredAnnotations());
AnnotationValue[] result = packageInfo.getAnnotations();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<AnnotationValue> actual = new HashSet<AnnotationValue>();
for (AnnotationValue f : result)
actual.add(f);
getLog().debug("Expected annotations=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected void assertParameterAnnotations(Constructor<?> constructor, ConstructorInfo constructorInfo) throws Throwable
{
Annotation[][] annotations = constructor.getParameterAnnotations();
ParameterInfo[] parameters = constructorInfo.getParameters();
for (int i = 0; i < annotations.length; ++i)
assertParameterAnnotations(annotations[i], parameters[i]);
}
protected void assertParameterAnnotations(Annotation[] annotations, ParameterInfo parameter) throws Throwable
{
Set<AnnotationValue> expected = getExpectedAnnotations(annotations);
AnnotationValue[] result = parameter.getAnnotations();
if (expected.isEmpty())
{
assertEmpty(result);
return;
}
assertNotNull(result);
assertEquals(expected.size(), result.length);
Set<AnnotationValue> actual = new HashSet<AnnotationValue>();
for (AnnotationValue f : result)
actual.add(f);
getLog().debug(parameter.getName() + " expected parameter annotations=" + expected + " actual=" + actual);
assertEquals(expected, actual);
}
protected Set<AnnotationValue> getExpectedAnnotations(Annotation[] annotations)
{
Set<AnnotationValue> expected = new HashSet<AnnotationValue>();
for (Annotation annotation : annotations)
{
Class<?> type = annotation.annotationType();
AnnotationInfoImpl info = new AnnotationInfoImpl(type.getName(), type.getModifiers());
// TODO JBMICROCONT-127 attributes
AnnotationValue a = new AnnotationValueImpl(info, new HashMap<String, Value>(), annotation);
expected.add(a);
}
return expected;
}
protected void assertTypeEquals(String context, TypeInfo expected, TypeInfo actual) throws Exception
{
assertEquals(expected, actual);
if (expected instanceof ClassInfo)
{
ClassInfo expectedClassInfo = (ClassInfo) expected;
ClassInfo actualClassInfo = (ClassInfo) actual;
assertEquals(context, expectedClassInfo.getOwnerType(), actualClassInfo.getOwnerType());
assertEquals(context, expectedClassInfo.getRawType(), actualClassInfo.getRawType());
TypeInfo[] expectedTypeArgs = expectedClassInfo.getActualTypeArguments();
TypeInfo[] actualTypeArgs = expectedClassInfo.getActualTypeArguments();
if (expectedTypeArgs == null)
assertNull(context, actualTypeArgs);
else
{
assertNotNull(context, actualTypeArgs);
getLog().debug("Checking type args for " + context + " expected: " + Arrays.asList(expectedTypeArgs) + " actual: " + Arrays.asList(actualTypeArgs));
assertEquals(expectedTypeArgs.length, actualTypeArgs.length);
for (int i = 0; i < expectedTypeArgs.length; ++i)
assertTypeEquals(context + "arg" + i, expectedTypeArgs[i], actualTypeArgs[i]);
}
}
}
protected abstract TypeInfoFactory getTypeInfoFactory();
protected void configureLogging()
{
enableTrace("org.jboss.reflect");
}
}