Classes - Utilities to work with class hierarchies
This commit is contained in:
parent
604967af9c
commit
48252c20b5
4 changed files with 197 additions and 0 deletions
80
src/main/java/info/ebenoit/ebul/reflection/Classes.java
Normal file
80
src/main/java/info/ebenoit/ebul/reflection/Classes.java
Normal 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
src/test/java/info/ebenoit/ebul/reflection/CTest6.java
Normal file
9
src/test/java/info/ebenoit/ebul/reflection/CTest6.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package info.ebenoit.ebul.reflection;
|
||||||
|
|
||||||
|
|
||||||
|
public class CTest6
|
||||||
|
extends CTest5
|
||||||
|
implements ITest2
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
7
src/test/java/info/ebenoit/ebul/reflection/ITest2.java
Normal file
7
src/test/java/info/ebenoit/ebul/reflection/ITest2.java
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package info.ebenoit.ebul.reflection;
|
||||||
|
|
||||||
|
public interface ITest2
|
||||||
|
extends ITest1
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
101
src/test/java/info/ebenoit/ebul/reflection/TestClasses.java
Normal file
101
src/test/java/info/ebenoit/ebul/reflection/TestClasses.java
Normal 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue