Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2014 Daniel Bechler
   *
   * 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 de.danielbechler.diff.node;
 
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static java.util.Collections.unmodifiableSet;

Represents a part of an object. It could be the object itself, one of its properties, an item in a collection or a map entry. A node may have one parent node and any number of children. It also provides methods to read and write the property represented by this node on any object of the same type as the original object. Last but not least, a node knows how the associated property has changed compared to the base object.

Author(s):
Daniel Bechler
 
 @SuppressWarnings("UnusedDeclaration")
 public class DiffNode
 {
 	public static final DiffNode ROOT = null;
 
 	private final Accessor accessor;
 
 	private State state = .;
 	private DiffNode parentNode;
 	private Class<?> valueType;
 
 	public DiffNode(final Accessor accessorfinal Class<?> valueType)
 	{
 		this(accessorvalueType);
 	}
 
 	public DiffNode(final DiffNode parentNodefinal Accessor accessorfinal Class<?> valueType)
 	{
 		Assert.notNull(accessor"accessor");
 		this. = accessor;
 		this. = valueType;
 		setParentNode(parentNode);
 	}
 
 	public DiffNode(final Class<?> valueType)
 	{
 		this(, RootAccessor.getInstance(), valueType);
 	}
 
 	public DiffNode()
 	{
 		this(, RootAccessor.getInstance(), null);
 	}

Returns:
The state of this node.
 
 	public State getState()
 	{
 		return this.;
 	}

Parameters:
state The state of this node.
 
 	public void setState(final State state)
	{
		Assert.notNull(state"state");
		this. = state;
	}
	public boolean matches(final NodePath path)
	{
		return path.matches(getPath());
	}
	public boolean hasChanges()
	{
		if (isAdded() || isChanged() || isRemoved())
		{
			return true;
		}
		final AtomicBoolean result = new AtomicBoolean(false);
		{
			public void node(final DiffNode nodefinal Visit visit)
			{
				if (node.hasChanges())
				{
					result.set(true);
					visit.stop();
				}
			}
		});
		return result.get();
	}

Convenience method for getState() == DiffNode.State.ADDED
	public final boolean isAdded()
	{
		return  == .;
	}

Convenience method for getState() == DiffNode.State.CHANGED
	public final boolean isChanged()
	{
		return  == .;
	}

Convenience method for getState() == DiffNode.State.REMOVED
	public final boolean isRemoved()
	{
		return  == .;
	}

Convenience method for getState() == DiffNode.State.UNTOUCHED
	public final boolean isUntouched()
	{
		return  == .;
	}

Convenience method for getState() == DiffNode.State.CIRCULAR
	public boolean isCircular()
	{
		return  == .;
	}

Returns:
The absolute property path from the object root up to this node.
	public final NodePath getPath()
	{
		if ( != null)
		{
		}
		else if ( instanceof RootAccessor)
		{
			return NodePath.withRoot();
		}
		else
		{
		}
	}
	{
	}

Returns:
Returns the type of the property represented by this node, or null if unavailable.
	public Class<?> getValueType()
	{
		if ( != null)
		{
			return ;
		}
		if ( instanceof TypeAwareAccessor)
		{
		}
		return null;
	}

Allows for explicit type definition. However, if the accessor is TypeAware, getValueType() will always return the type returned by the accessor.

Parameters:
aClass The type of the value represented by this node.
	public void setType(final Class<?> aClass)
	{
		this. = aClass;
	}

Returns:
true if this node has children.
	public boolean hasChildren()
	{
		return !.isEmpty();
	}
	public int childCount()
	{
		return .size();
	}

Retrieve a child with the given property name relative to this node.

Parameters:
propertyName The name of the property represented by the child node.
Returns:
The requested child node or null.
	public DiffNode getChild(final String propertyName)
	{
		return getChild(new BeanPropertyElementSelector(propertyName));
	}

Retrieve a child that matches the given path element relative to this node.

Parameters:
pathElementSelector The path element of the child node to get.
Returns:
The requested child node or null.
	public DiffNode getChild(final ElementSelector pathElementSelector)
	{
		return .get(pathElementSelector);
	}

Retrieve a child that matches the given absolute path, starting from the current node.

Parameters:
nodePath The path from the object root to the requested child node.
Returns:
The requested child node or null.
	public DiffNode getChild(final NodePath nodePath)
	{
		if ( != null)
		{
		}
		else
		{
			return getChild(nodePath.getElementSelectors());
		}
	}

Retrieve a child that matches the given path element relative to this node.

Parameters:
selectors The path element of the child node to get.
Returns:
The requested child node or null.
	public DiffNode getChild(final List<ElementSelectorselectors)
	{
		Assert.notEmpty(selectors"selectors");
		final ElementSelector selector = selectors.get(0);
		if (selectors.size() == 1)
		{
			if (selector == RootElementSelector.getInstance())
			{
				return isRootNode() ? this : null;
			}
			else
			{
				return getChild(selector);
			}
		}
		else if (selectors.size() > 1)
		{
			final DiffNode child;
			if (selector == RootElementSelector.getInstance())
			{
				child = isRootNode() ? this : null;
			}
			else
			{
				child = getChild(selector);
			}
			if (child != null)
			{
				return child.getChild(selectors.subList(1, selectors.size()));
			}
		}
		return null;
	}

Adds a child to this node and sets this node as its parent node.

Parameters:
node The node to add.
	public boolean addChild(final DiffNode node)
	{
		if (node.isRootNode())
		{
			throw new IllegalArgumentException("Detected attempt to add root node as child. " +
					"This is not allowed and must be a mistake.");
		}
		else if (node == this)
		{
			throw new IllegalArgumentException("Detected attempt to add a node to itself. " +
					"This would cause inifite loops and must never happen.");
		}
		else if (node.getParentNode() != null && node.getParentNode() != this)
		{
			throw new IllegalArgumentException("Detected attempt to add child node that is already the " +
					"child of another node. Adding nodes multiple times is not allowed, since it could " +
					"cause infinite loops.");
		}
		final ElementSelector pathElementSelector = node.getElementSelector();
		if (node.getParentNode() == null)
		{
			node.setParentNode(this);
			.put(pathElementSelectornode);
		}
		else if (node.getParentNode() == this)
		{
			.put(pathElementSelectornode);
		}
		else
		{
			throw new IllegalStateException("Detected attempt to replace the parent node of node at path '" + getPath() + "'");
		}
		if ( == . && node.hasChanges())
		{
		}
		return true;
	}

Visit this and all child nodes.

Parameters:
visitor The visitor to use.
	public final void visit(final Visitor visitor)
	{
		final Visit visit = new Visit();
		try
		{
			visit(visitorvisit);
		}
		catch (final StopVisitationException ignored)
		{
		}
	}
	protected final void visit(final Visitor visitorfinal Visit visit)
	{
		try
		{
			visitor.node(thisvisit);
		}
		catch (final StopVisitationException e)
		{
			visit.stop();
		}
		if (visit.isAllowedToGoDeeper() && hasChildren())
		{
			visitChildren(visitor);
		}
		if (visit.isStopped())
		{
		}
	}

Visit all child nodes but not this one.

Parameters:
visitor The visitor to use.
	public final void visitChildren(final Visitor visitor)
	{
		for (final DiffNode child : .values())
		{
			try
			{
				child.visit(visitor);
			}
			catch (final StopVisitationException e)
			{
				return;
			}
		}
	}
	public final void visitParents(final Visitor visitor)
	{
		final Visit visit = new Visit();
		if ( != null)
		{
			visitor.node(visit);
			if (!visit.isStopped())
			{
			}
		}
	}

If this node represents a bean property this method returns all annotations of its getter.

Returns:
A set of annotations of this nodes property getter or an empty set.
	{
		{
		}
		return unmodifiableSet(Collections.<Annotation>emptySet());
	}
	public <T extends Annotation> T getPropertyAnnotation(final Class<T> annotationClass)
	{
		{
		}
		return null;
	}

If this node represents a bean property, this method will simply return its name. Otherwise it will return the property name of its closest bean property representing ancestor. This way intermediate nodes like those representing collection, map or array items will be semantically tied to their container objects.

That is especially useful for inclusion and exclusion rules. For example, when a List is explicitly included by property name, it would be weird if the inclusion didn't also apply to its items.

	{
		{
		}
		else if ( != null)
		{
		}
		return null;
	}

Returns true when this node represents a bean property and can therefore be queried for property specific information like annotations or property types. But there will also be nodes that represent collection items, map entries, etc. In those cases this method will return false.
	public final boolean isPropertyAware()
	{
		return  instanceof PropertyAwareAccessor;
	}
	public final boolean isRootNode()
	{
		return  instanceof RootAccessor;
	}

Convenience method for getState() == DiffNode.State.IGNORED
	public final boolean isIgnored()
	{
		return  == .;
	}
	public boolean isExcluded()
	{
		if ( instanceof ExclusionAware)
		{
		}
		return false;
	}
	// TODO These categories should also contain the ones configured via CategoryService
	public final Set<StringgetCategories()
	{
		final Set<Stringcategories = new TreeSet<String>();
		if ( != null)
		{
		}
		if ( instanceof CategoryAware)
		{
			final Set<StringcategoriesFromAccessor = ((CategoryAware).getCategoriesFromAnnotation();
			if (categoriesFromAccessor != null)
			{
				categories.addAll(categoriesFromAccessor);
			}
		}
		return categories;
	}

Returns:
The parent node, if any.
	{
		return ;
	}

Sets the parent node.

Parameters:
parentNode The parent of this node. May be null, if this is a root node.
	protected final void setParentNode(final DiffNode parentNode)
	{
		if (this. != null && this. != parentNode)
		{
			throw new IllegalStateException("The parent of a node cannot be changed, once it's set.");
		}
		this. = parentNode;
	}
	public Object get(final Object target)
	{
		return .get(target);
	}
	public void set(final Object targetfinal Object value)
	{
		.set(targetvalue);
	}
	public void unset(final Object target)
	{
		.unset(target);
	}
	public Object canonicalGet(Object target)
	{
		if ( != null)
		{
			target = .canonicalGet(target);
		}
		return .get(target);
	}
	public void canonicalSet(Object targetfinal Object value)
	{
		if ( != null)
		{
			target = .canonicalGet(target);
		}
		.set(targetvalue);
	}
	public void canonicalUnset(Object target)
	{
		if ( != null)
		{
			target = .canonicalGet(target);
		}
		.unset(target);
	}
	public int hashCode()
	{
		return .hashCode();
	}
	public boolean equals(final Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}
		final DiffNode that = (DiffNodeo;
		if (!.equals(that.accessor))
		{
			return false;
		}
		return true;
	}
	public String toString()
	{
		final StringBuilder sb = new StringBuilder();
		sb.append("(");
		sb.append("state=");
		if (getValueType() != null)
		{
		}
		if (childCount() == 1)
		{
			sb.append(", ").append(childCount()).append(" child");
		}
		else if (childCount() > 1)
		{
			sb.append(", ").append(childCount()).append(" children");
		}
		else
		{
			sb.append(", no children");
		}
		{
			sb.append(", categorized as ").append(getCategories());
		}
		sb.append(", accessed via ").append();
		sb.append(')');
		return sb.toString();
	}

Returns:
Returns the path to the first node in the hierarchy that represents the same object instance as this one. (Only if isCircular() returns true.
	{
	}
	public void setCircleStartPath(final NodePath circularStartPath)
	{
		this. = circularStartPath;
	}
	{
	}
	public void setCircleStartNode(final DiffNode circleStartNode)
	{
		this. = circleStartNode;
	}

The state of a DiffNode representing the difference between two objects.
	public enum State
	{
The value has been added to the working object.
		ADDED,

The value has been changed compared to the base object.
		CHANGED,

The value has been removed from the working object.
		REMOVED,

The value is identical between working and base
		UNTOUCHED,

Special state to mark circular references
		CIRCULAR,

The value has not been looked at and has been ignored.
		IGNORED
	}

Visitor to traverse a node graph.
	public static interface Visitor
	{
		void node(DiffNode nodeVisit visit);
	}
New to GrepCode? Check out our FAQ X