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

org.whaka.util.reflection.comparison.ComplexComparisonResult Maven / Gradle / Ivy

package org.whaka.util.reflection.comparison;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import org.whaka.util.UberObjects;
import org.whaka.util.reflection.properties.ClassPropertyKey;
import org.whaka.util.reflection.properties.ClassPropertyStack;

/**
 * 

Instance of this class represents 'complex' recursive result of performed comparison for two objects. * This result may contain other comparison results mapped by instances of the {@link ClassPropertyKey} * pointing to the specific (if possible) properties of the objects. * *

Example: *

 * 	class SimplePerson {
 * 		public String name;
 * 		public int age;
 * 		public boolean male;
 * 	}
* Now imagine we have two instances of this class: *
    *
  • SimplePerson{name="Martin", age=30, male=true} *
  • SimplePerson{name="Martina", age=30, male=false} *
* If you want to compare these two object you probably would like to get some more informative result, * than single false. This way you could create instance of this complex comparison result, with * fields like this: *
    *
  • Actual: SimplePerson{name="Martin", age=30, male=true} *
  • Expected: SimplePerson{name="Martina", age=30, male=false} *
  • Success: false *
  • Property results: *
      *
    • SimplePerson#name: ComparisonResult{actual="Martin", expected="Martina"} *
    • SimplePerson#age: ComparisonResult{success} *
    • SimplePerson#male: ComparisonResult{actual=true, expected=false} *
    *
  • *
* The same recursive way if some other object contains SimplePerson as a field - you can compare them and return * complex result that will contain this result as one of the "property results". And we can go deeper! * *

Of course you always can use {@link #isSuccess()} to get simple "yes/no" answer if there's no need * for such a depth. Complex comparison result is assumed to be successful, if all property results * from {@link #getPropertyResults()} are successful. * *

Note: due to specifics of the {@link ClassPropertyKey} class single complex result may contain * property results mapped by keys pointing to any class - no validation is performed. But main recommendation is * for a single complex result to contain results for properties 'declared' by the class of compared objects, or its * superclasses. So if class JobPosition declares fields "String title" and "SimplePerson employee", then complex result * for this class should contain only properties declared in JobPosition or it's ancestors. */ public class ComplexComparisonResult extends ComparisonResult { private final Map propertyResults = new LinkedHashMap<>(); /** * Construct complex result using specified map of sub results. Specified values represent compared objects. * Specified performer represents the one, performer comparison. * * @see ComparisonResult#ComparisonResult(Object, Object, ComparisonPerformer, boolean) */ public ComplexComparisonResult(Object actual, Object expected, ComparisonPerformer comparisonPerformer, Map unequalProperties) { super(actual, expected, comparisonPerformer, true); if (unequalProperties != null) { Preconditions.checkArgument(!unequalProperties.containsKey(null), "Property key cannot be null!"); propertyResults.putAll(unequalProperties); } } /** *

Returns map that describes results of comparison performed for properties of objects from this result. * Instances of {@link ClassPropertyKey} are used as keys of the map pointing to the specific comparison result * for specific property. * *

This result is assumed to be successful if all the results in the map are successful. */ public Map getPropertyResults() { return Collections.unmodifiableMap(propertyResults); } /** *

Method creates flat representation of the property results. * *

Result map will contain only simple comparison results, mapped by {@link ClassPropertyStack} instances. * All complex subresults will be also flattened. * *

Property stacks are built this way: if this result contains simple sub-result with key String#length() * the result map will contain this sub-result with key {String#length()} (it's a stack of one element) * or {length()} (it's a call-string stack representation). And if this result contains complex sub-result * with key String#getBytes() and it contains simple sub-result with key byte[]#length * then result map will contain this simple sub-sub-result with key {String#getBytes()->byte[]#length} * or {getBytes().length} * *

Note: all the keys in the result map will contain null as parent, for calling of this * method is considered to be the beginning of a stack. * * @see #flatten(ClassPropertyStack) */ public Map flatten() { return flatten(null); } /** * Analogue of the {@link #flatten()} method, but all the keys in the result map will contains specified stack * as parent. */ public Map flatten(ClassPropertyStack parent) { Map map = new LinkedHashMap<>(); for (Map.Entry e : getPropertyResults().entrySet()) { ClassPropertyStack stack = new ClassPropertyStack(parent, e.getKey()); ComparisonResult result = e.getValue(); if (result instanceof ComplexComparisonResult) map.putAll(((ComplexComparisonResult) result).flatten(stack)); else map.put(stack, result); } return map; } /** * Complex comparison result assumed to be successful if all the property comparison result * from {@link #getPropertyResults()} returns true from {@link #isSuccess()}. */ @Override public boolean isSuccess() { return getPropertyResults().values().stream() .filter(Objects::nonNull) .allMatch(ComparisonResult::isSuccess); } @Override public String toString() { return MoreObjects.toStringHelper(ComplexComparisonResult.class) .add("success", isSuccess()) .add("property-results", getPropertyResults().keySet()) .add("actual", UberObjects.toString(getActual())) .add("expected", UberObjects.toString(getExpected())) .add("performer", getComparisonPerformer()) .toString(); } @Override public int hashCode() { return Objects.hash(getActual(), getExpected(), getComparisonPerformer(), getPropertyResults()); } @Override public boolean equals(Object object) { if (object != null && getClass() == object.getClass()) { ComplexComparisonResult that = (ComplexComparisonResult) object; return getActual() == that.getActual() && getExpected() == that.getExpected() && Objects.equals(getComparisonPerformer(), that.getComparisonPerformer()) && Objects.equals(getPropertyResults(), that.getPropertyResults()); } return false; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy