All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.srplib.reflection.objectgraph.ObjectGraph Maven / Gradle / Ivy

package org.srplib.reflection.objectgraph;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.srplib.contract.Argument;
import org.srplib.reflection.ReflectionUtils;
import org.srplib.support.Predicate;

/**
 * Encapsulates object graph navigation algorithm.
 *
 * 
    *
  • * iterates java container structures: (Map, Collection, array, etc.). *
  • *
  • * iterates declared fields of java classes using reflection API. *
  • *
  • * handles cyclic references. *
  • *
* *

Useful where object graph navigation is required: debugging, logging, conversion, etc.

* * @author Anton Pechinsky */ public class ObjectGraph implements Element { private Object root; private Set visitedIdentities = new HashSet(); private Predicate> filter; /** * Creates object graph with specified root and class filter. * * @param root Object root object. {@code null} is supported * @param filter a predicate defining should or not implementation examine class internals. */ public ObjectGraph(Object root, Predicate> filter) { Argument.checkNotNull(root, "root must not be null!"); Argument.checkNotNull(filter, "filter must not be null!"); this.root = root; this.filter = filter; } /** * Creates object graph with specified root. * * @param root Object root object. {@code null} is supported. */ public ObjectGraph(Object root) { this(root, new StandardTraversableClassesFilter()); } @Override public void accept(Visitor visitor) { traverse(root, visitor); } private void traverse(Object object, Visitor visitor) { if (object == null) { return; } if (!isTraversable(object)) { return; } if (isVisited(object)) { return; } rememberVisited(object); visitor.visit(object); if (ReflectionUtils.isMap(object.getClass())) { traverseMap((Map) object, visitor); } else if (ReflectionUtils.isCollection(object.getClass())) { traverseCollection((Collection) object, visitor); } else if (ReflectionUtils.isArray(object.getClass())) { traverseArray((Object[]) object, visitor); } else { traverseDeclaredFields(object.getClass(), object, visitor); } } private void rememberVisited(Object object) { int identity = identity(object); visitedIdentities.add(identity); } private boolean isVisited(Object object) { int identity = identity(object); return visitedIdentities.contains(identity); } private int identity(Object object) { return System.identityHashCode(object); } private void traverseMap(Map map, Visitor visitor) { for (Object entryObject : map.entrySet()) { Map.Entry entry = (Map.Entry) entryObject; traverse(entry.getKey(), visitor); traverse(entry.getValue(), visitor); } } private void traverseCollection(Collection collection, Visitor visitor) { for (Object valueItem : collection) { traverse(valueItem, visitor); } } private void traverseArray(Object[] array, Visitor visitor) { for (Object valueItem : array) { traverse(valueItem, visitor); } } private void traverseDeclaredFields(Class objectClass, Object object, Visitor visitor) { if (objectClass == Object.class) { return; } for (Field field : objectClass.getDeclaredFields()) { if (ReflectionUtils.isSyntheticName(field.getName())) { continue; } Object fieldValue = ReflectionUtils.getFieldValue(object, field); traverse(fieldValue, visitor); } traverseDeclaredFields(objectClass.getSuperclass(), object, visitor); } private boolean isTraversable(Object object) { return object != null && filter.test(object.getClass()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy