Classes - Utilities to work with class hierarchies

This commit is contained in:
Emmanuel BENOîT 2015-09-15 08:58:37 +02:00
parent 604967af9c
commit 48252c20b5
4 changed files with 197 additions and 0 deletions

View file

@ -0,0 +1,80 @@
package info.ebenoit.ebul.reflection;
import java.util.ArrayList;
import java.util.HashSet;
/**
* Utility methods to query classes and interfaces.
*
* @author <a href="mailto:ebenoit@ebenoit.info">E. Benoît</a>
*/
public final class Classes
{
/**
* List all classes a class inherits from.
*
* @param cls
* the class to examine
* @return the list of ancestors, including the class itself
*/
public static < T > ArrayList< Class< ? super T > > getAncestors( final Class< T > cls )
{
final ArrayList< Class< ? super T > > result = new ArrayList< >( );
Class< ? super T > current = cls;
while ( current != null ) {
result.add( current );
current = current.getSuperclass( );
}
return result;
}
/**
* Find all types a class is compatible with: itself, its ancestors, and all implemented interfaces.
*
* @param cls
* the class to examine
* @return the set of compatible types
*/
public static HashSet< Class< ? > > getAllTypes( final Class< ? > cls )
{
final HashSet< Class< ? > > found = new HashSet< >( );
Class< ? > current = cls;
while ( current != null ) {
found.add( current );
Classes.addInterfaces( current , found );
current = current.getSuperclass( );
}
return found;
}
/**
* Internal method used by {@link #getAllTypes(Class)} to add all interfaces recursively.
*
* @param current
* the class or interface being examined
* @param found
* the result
*/
private static void addInterfaces( final Class< ? > current , final HashSet< Class< ? > > found )
{
if ( current == null ) {
return;
}
final Class< ? >[] interfaces = current.getInterfaces( );
final int len = interfaces.length;
for ( int i = 0 ; i < len ; i++ ) {
final Class< ? > itf = interfaces[ i ];
if ( found.add( itf ) ) {
Classes.addInterfaces( itf , found );
}
}
}
}

View file

@ -0,0 +1,9 @@
package info.ebenoit.ebul.reflection;
public class CTest6
extends CTest5
implements ITest2
{
// EMPTY
}

View file

@ -0,0 +1,7 @@
package info.ebenoit.ebul.reflection;
public interface ITest2
extends ITest1
{
}

View file

@ -0,0 +1,101 @@
package info.ebenoit.ebul.reflection;
import java.util.HashSet;
import org.junit.Assert;
import org.junit.Test;
/** Tests for {@link Classes} */
public class TestClasses
{
/** Test: {@link Classes#getAncestors(Class)} called on Object.class */
@Test
public void getAncestorsObject( )
{
@SuppressWarnings( "unchecked" )
final Class< ? super Object > expected[] = new Class[] {
Object.class
};
final Class< ? super Object > result[] = Classes.getAncestors( Object.class ).toArray( expected );
Assert.assertArrayEquals( expected , result );
}
/** Test: {@link Classes#getAncestors(Class)} called on an actual hierarchy */
@Test
public void getAncestors( )
{
@SuppressWarnings( "unchecked" )
final Class< ? super CTest4 > expected[] = new Class[] {
CTest4.class , CTest3.class , CTest2.class , CTest1.class , Object.class
};
final Class< ? super CTest4 > result[] = Classes.getAncestors( CTest4.class ).toArray( expected );
Assert.assertArrayEquals( expected , result );
}
/** Test: {@link Classes#getAllTypes(Class)} called on Object.class */
@Test
public void getAllTypesObject( )
{
final Class< ? > expected[] = new Class[] {
Object.class
};
final Class< ? > result[] = Classes.getAllTypes( Object.class ).toArray( expected );
Assert.assertArrayEquals( expected , result );
}
/** Test: {@link Classes#getAllTypes(Class)} called on a hierarchy with no implemented interfaces */
@Test
public void getAllTypesHierarchy( )
{
final HashSet< Class< ? > > expected = new HashSet< Class< ? > >( );
expected.add( Object.class );
expected.add( CTest1.class );
expected.add( CTest2.class );
expected.add( CTest3.class );
expected.add( CTest4.class );
final HashSet< Class< ? > > result = Classes.getAllTypes( CTest4.class );
Assert.assertEquals( expected , result );
}
/** Test: {@link Classes#getAllTypes(Class)} called on a hierarchy with one implemented interfaces */
@Test
public void getAllTypesInterface( )
{
final HashSet< Class< ? > > expected = new HashSet< Class< ? > >( );
expected.add( Object.class );
expected.add( ITest1.class );
expected.add( CTest5.class );
final HashSet< Class< ? > > result = Classes.getAllTypes( CTest5.class );
Assert.assertEquals( expected , result );
}
/** Test: {@link Classes#getAllTypes(Class)} called on a hierarchy with redundant interfaces */
@Test
public void getAllTypesInterfaces( )
{
final HashSet< Class< ? > > expected = new HashSet< Class< ? > >( );
expected.add( Object.class );
expected.add( ITest1.class );
expected.add( ITest2.class );
expected.add( CTest5.class );
expected.add( CTest6.class );
final HashSet< Class< ? > > result = Classes.getAllTypes( CTest6.class );
Assert.assertEquals( expected , result );
}
}