/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.util; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.Set; public class ObjectTraverser { public static class DefaultVisitorBase implements Visitor { int depth = 0; int maxDepth = 10000; Set<Instance> instances = new HashSet<Instance>(); @Override public void exitObject(ObjectTraverser traverser, Object obj, Object parent, Field parentField, int index) { depth--; } @Override public boolean visitObject(ObjectTraverser traverser, Object obj, Object parent, Field parentField, int index) { if (depth == maxDepth) { return false; } if (obj != null && instances.add(new Instance(obj))) { depth++; return true; } return false; } @Override public void visitPrimitive(ObjectTraverser traverser, Object prim, Object parent, Field parentField) { } } public static final class Instance { final Object obj; protected Instance(Object obj) { super(); this.obj = obj; } @Override public boolean equals(Object o) { if (o instanceof Instance) { return obj == ((Instance) o).obj; } return false; } @Override public int hashCode() { return System.identityHashCode(obj); } } public static interface Visitor { public void exitObject(ObjectTraverser traverser, Object obj, Object parent, Field parentField, int index); public boolean visitObject(ObjectTraverser traverser, Object obj, Object parent, Field parentField, int index); public void visitPrimitive(ObjectTraverser traverser, Object prim, Object parent, Field parentField); } private void traverse(Object obj, Object parent, Field parentField, Visitor visitor, int index) throws Exception { if (visitor.visitObject(this, obj, parent, parentField, index) && obj != null && (parentField == null || !parentField.getType().isPrimitive())) { Class<?> oclass = obj.getClass(); if (oclass.isArray()) { if (!oclass.getComponentType().isPrimitive()) { int length = Array.getLength(obj); for (int i = 0; i < length; i++) { traverse(Array.get(obj, i), parent, parentField, visitor, i); } } } else { while (oclass != null) { for (Field field : oclass.getDeclaredFields()) { if (Modifier.isStatic(field.getModifiers())) { continue; } field.setAccessible(true); Object value = field.get(obj); if (field.getType().isPrimitive()) { visitor.visitPrimitive(this, value, obj, field); } else { traverse(value, obj, field, visitor, -1); } } oclass = oclass.getSuperclass(); } } visitor.exitObject(this, obj, parent, parentField, index); } } public void traverse(Object obj, Visitor visitor) throws Exception { traverse(obj, null, null, visitor, -1); } }