ExtensionWalker.java
/***************************************************************************
Copyright 2014 Emily Estes
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
***************************************************************************/
package net.metanotion.util.reflect;
import java.lang.reflect.Field;
import java.util.Arrays;
import net.metanotion.util.Extends;
/** This class simplifies visiting the transitive closure of all fields in a class marked with the
{@literal @}{@link net.metanotion.util.Extends} annotation. Users implement the ClassVisitor interface
and then call {@link #reduce} with their instance of ClassVisitor.
*/
public final class ExtensionWalker {
/** This interface is implemented by the class that wants to traverse the nodes found by the
{@link net.metanotion.util.reflect.ExtensionWalker#visit} method. */
public interface ClassVisitor {
/** Process the node found from the list of fields in the stack.
@param stack The list of fields traversed to reach this class.
@param current The class we're currently processing(reached by following the stack).
*/
public void visit(Field[] stack, Class current);
}
/** Transitively visit all the fields marked with the {@literal @}{@link net.metanotion.util.Extends} annotation
and call the provided visitor on each class.
@param visitor The instance of the visitor to call on each class reached.
@param root The class to start with.
*/
public static void visit(final ClassVisitor visitor, final Class root) { reduce(visitor, new Field[0], root); }
private static void reduce(ClassVisitor visitor, Field[] stack, Class current) {
for(final Field f: current.getFields()) {
f.setAccessible(true);
final Field[] f1 = Arrays.copyOf(stack, stack.length + 1);
f1[stack.length] = f;
if(f.getAnnotation(Extends.class) != null) {
reduce(visitor, f1, f.getType());
}
}
visitor.visit(stack, current);
}
}