diff --git a/src/main/java/info/ebenoit/ebul/reflection/MemberFinder.java b/src/main/java/info/ebenoit/ebul/reflection/MemberFinder.java
new file mode 100644
index 0000000..1c559fe
--- /dev/null
+++ b/src/main/java/info/ebenoit/ebul/reflection/MemberFinder.java
@@ -0,0 +1,351 @@
+package info.ebenoit.ebul.reflection;
+
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+
+
+/**
+ * Helper to find methods and fields in a class hierarchy.
+ * <p>
+ * This class can be used to look for specific members in a class hierarchy. It can be set up so that it also checks
+ * interfaces.
+ *
+ * @param <T>
+ *            the type of members being examined
+ *
+ * @author <a href="mailto:ebenoit@ebenoit.info">E. BenoƮt</a>
+ */
+public class MemberFinder< T >
+{
+
+	/** Function to extract methods from a class */
+	public static final Function< Class< ? > , Method[] > METHOD_EXTRACTOR = c -> c.getMethods( );
+	/** Function to extract fields from a class */
+	public static final Function< Class< ? > , Field[] > FIELD_EXTRACTOR = c -> c.getFields( );
+
+
+	/**
+	 * Lists methods matching some criteria
+	 * <p>
+	 * This method is a shortcut that configures a {@link MemberFinder} instance for methods, and applies it.
+	 * 
+	 * @param target
+	 *            the class to examine
+	 * @param methodFilter
+	 *            the method filtering function (may be <code>null</code>)
+	 * @param classFilter
+	 *            the class filtering function (may be <code>null</code>)
+	 * @param interfaces
+	 *            whether interfaces should be examined too
+	 * @param classesFirst
+	 *            if interfaces are to be examined, <code>true</code> if superclasses should be examined first
+	 * @return an array of methods matching the specified criteria
+	 */
+	public static final ArrayList< Method > getAllMethods( final Class< ? > target ,
+			final Predicate< Method > methodFilter , final Predicate< Class< ? > > classFilter ,
+			final boolean interfaces , final boolean classesFirst )
+	{
+		final ArrayList< Method > result = new ArrayList< >( );
+		MemberFinder.getAllMethods( result , target , methodFilter , classFilter , interfaces , classesFirst );
+		return result;
+	}
+
+
+	/**
+	 * Lists methods matching some criteria
+	 * <p>
+	 * This method is a shortcut that configures a {@link MemberFinder} instance for methods, and applies it.
+	 * 
+	 * @param output
+	 *            the collection to which matching methods will be added
+	 * @param target
+	 *            the class to examine
+	 * @param methodFilter
+	 *            the method filtering function (may be <code>null</code>)
+	 * @param classFilter
+	 *            the class filtering function (may be <code>null</code>)
+	 * @param interfaces
+	 *            whether interfaces should be examined too
+	 * @param classesFirst
+	 *            if interfaces are to be examined, <code>true</code> if superclasses should be examined first
+	 * @return the output collection to which methods matching the specified criteria were added
+	 */
+	public static final Collection< Method > getAllMethods( final Collection< Method > output ,
+			final Class< ? > target , final Predicate< Method > methodFilter ,
+			final Predicate< Class< ? > > classFilter , final boolean interfaces , final boolean classesFirst )
+	{
+		final MemberFinder< Method > mf = new MemberFinder< >( MemberFinder.METHOD_EXTRACTOR , interfaces );
+		mf.setClassesFirst( classesFirst );
+		mf.setClassFilter( classFilter );
+		mf.setMemberFilter( methodFilter );
+		mf.find( output , target );
+		return output;
+	}
+
+
+	/**
+	 * Lists fields matching some criteria
+	 * <p>
+	 * This method is a shortcut that configures a {@link MemberFinder} instance for fields, and applies it.
+	 * 
+	 * @param target
+	 *            the class to examine
+	 * @param fieldFilter
+	 *            the field filtering function (may be <code>null</code>)
+	 * @param classFilter
+	 *            the class filtering function (may be <code>null</code>)
+	 * @return an array of fields matching the specified criteria
+	 */
+	public static final ArrayList< Field > getAllFields( final Class< ? > target ,
+			final Predicate< Field > fieldFilter , final Predicate< Class< ? > > classFilter )
+	{
+		final ArrayList< Field > result = new ArrayList< >( );
+		MemberFinder.getAllFields( result , target , fieldFilter , classFilter );
+		return result;
+	}
+
+
+	/**
+	 * Lists fields matching some criteria
+	 * <p>
+	 * This method is a shortcut that configures a {@link MemberFinder} instance for fields, and applies it.
+	 * 
+	 * @param output
+	 *            the collection to which matching fields will be added
+	 * @param target
+	 *            the class to examine
+	 * @param fieldFilter
+	 *            the field filtering function (may be <code>null</code>)
+	 * @param classFilter
+	 *            the class filtering function (may be <code>null</code>)
+	 * @return the output collection to which fields matching the specified criteria were added
+	 */
+	public static final Collection< Field > getAllFields( final Collection< Field > output , final Class< ? > target ,
+			final Predicate< Field > fieldFilter , final Predicate< Class< ? > > classFilter )
+	{
+		final MemberFinder< Field > mf = new MemberFinder< >( MemberFinder.FIELD_EXTRACTOR , false );
+		mf.setClassFilter( classFilter );
+		mf.setMemberFilter( fieldFilter );
+		mf.find( output , target );
+		return output;
+	}
+
+	/** Function to use in order to extract the class' members */
+	protected final Function< Class< ? > , T[] > extractor;
+	/** Filter function for classes */
+	protected Predicate< Class< ? > > classFilter;
+	/** Filter function for members */
+	protected Predicate< T > memberFilter;
+	/** <code>true</code> if the finder will go through interfaces, <code>false</code> if it will ignore them */
+	protected final boolean interfaces;
+	/**
+	 * If the finder has to go through interfaces, this flag indicates whether they will be examined before or after a
+	 * class' superclass. It has no effect if {@link #interfaces} is set to <code>false</code>.
+	 */
+	protected boolean classesFirst;
+
+
+	/**
+	 * Initialises the member finder by setting the appropriate extractor and whether or not it will go through
+	 * interfaces.
+	 * <p>
+	 * By default, no class or member filtering functions are set, and superclasses will be examined before implemented
+	 * interfaces.
+	 *
+	 * @param extractor
+	 *            the function to use in order to extract the class' members
+	 * @param interfaces
+	 *            <code>true</code> if the finder must go through interfaces, <code>false</code> if it must ignore them
+	 */
+	public MemberFinder( final Function< Class< ? > , T[] > extractor , final boolean interfaces )
+	{
+		this.extractor = extractor;
+		this.interfaces = interfaces;
+		this.classesFirst = true;
+	}
+
+
+	/**
+	 * Gets the member extraction function
+	 *
+	 * @return the function that extracts class members
+	 */
+	public Function< Class< ? > , T[] > getExtractor( )
+	{
+		return this.extractor;
+	}
+
+
+	/**
+	 * Gets the interface-checking flag
+	 *
+	 * @return <code>true</code> if the finder will go through interfaces, <code>false</code> if it will ignore them
+	 */
+	public boolean willCheckInterfaces( )
+	{
+		return this.interfaces;
+	}
+
+
+	/**
+	 * Gets the class filtering function
+	 *
+	 * @return the class filtering function, or <code>null</code> if no class filtering has been configured
+	 */
+	public Predicate< Class< ? > > getClassFilter( )
+	{
+		return this.classFilter;
+	}
+
+
+	/**
+	 * Sets the class filtering function
+	 *
+	 * @param classFilter
+	 *            the new class filtering function, or <code>null</code> to disable class filtering
+	 */
+	public void setClassFilter( final Predicate< Class< ? > > classFilter )
+	{
+		this.classFilter = classFilter;
+	}
+
+
+	/**
+	 * Gets the member filtering function
+	 *
+	 * @return the member filtering function
+	 */
+	public Predicate< T > getMemberFilter( )
+	{
+		return this.memberFilter;
+	}
+
+
+	/**
+	 * Sets the member filtering function
+	 *
+	 * @param memberFilter
+	 *            the member filtering function
+	 */
+	public void setMemberFilter( final Predicate< T > memberFilter )
+	{
+		this.memberFilter = memberFilter;
+	}
+
+
+	/**
+	 * Checks whether superclasses are to be examined before or after interfaces.
+	 * <p>
+	 * Note: meaningless if {@link #willCheckInterfaces()} is <code>false</code>.
+	 *
+	 * @return <code>true</code> if superclasses are examined before interfaces, <code>false</code> if interfaces are
+	 *         examined before superclasses.
+	 */
+	public boolean willCheckClassesFirst( )
+	{
+		return this.classesFirst;
+	}
+
+
+	/**
+	 * Selects whether superclasses are to be examined before or after interfaces.
+	 * <p>
+	 * Note: meaningless if {@link #willCheckInterfaces()} is <code>false</code>.
+	 *
+	 * @param classesFirst
+	 *            <code>true</code> if superclasses are to be examined before interfaces, <code>false</code> if
+	 *            interfaces are to be examined before superclasses.
+	 */
+	public void setClassesFirst( final boolean classesFirst )
+	{
+		this.classesFirst = classesFirst;
+	}
+
+
+	/**
+	 * Finds members matching the currently configured criteria.
+	 *
+	 * @param output
+	 *            the collection to which the selected members will be added
+	 * @param target
+	 *            the class to examine
+	 * @return the collection to which the selected members were added
+	 */
+	public Collection< T > find( final Collection< T > output , final Class< ? > target )
+	{
+		// We only need to make sure we're not going through the same class twice if we have to go through interfaces
+		final HashSet< Class< ? > > checked;
+		if ( this.interfaces ) {
+			checked = new HashSet< >( );
+		} else {
+			checked = null;
+		}
+
+		this.findInternal( output , checked , target );
+		return output;
+	}
+
+
+	/**
+	 * Internal method that implements the actual look-up.
+	 *
+	 * @param output
+	 *            the collection to which the selected members will be added
+	 * @param checked
+	 *            the set of classes that were already examined; will be <code>null</code> if {@link #interfaces} is set
+	 *            to <code>false</code>.
+	 * @param target
+	 *            the class being examined
+	 */
+	protected void findInternal( final Collection< T > output , final HashSet< Class< ? > > checked ,
+			final Class< ? > target )
+	{
+		if ( target == null || this.classFilter != null && !this.classFilter.test( target ) ) {
+			return;
+		}
+		checked.add( target );
+
+		if ( this.interfaces && !this.classesFirst ) {
+			for ( final Class< ? > intf : target.getInterfaces( ) ) {
+				if ( !checked.contains( intf ) ) {
+					this.findInternal( output , checked , intf );
+				}
+			}
+		}
+
+		this.findInternal( output , checked , target.getSuperclass( ) );
+
+		if ( this.interfaces && this.classesFirst ) {
+			this.checkInterfaces( output , checked , target );
+		}
+	}
+
+
+	/**
+	 * Internal method that checks a class' interfaces recursively
+	 *
+	 * @param output
+	 *            the collection to which the selected members will be added
+	 * @param checked
+	 *            the set of classes that were already examined
+	 * @param target
+	 *            the class being examined
+	 */
+	private void checkInterfaces( final Collection< T > output , final HashSet< Class< ? > > checked ,
+			final Class< ? > target )
+	{
+		for ( final Class< ? > intf : target.getInterfaces( ) ) {
+			if ( !checked.contains( intf ) ) {
+				this.findInternal( output , checked , intf );
+			}
+		}
+	}
+
+}
\ No newline at end of file