/* * Copyright 2008, Unitils.org * * 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 org.unitils.reflectionassert.comparator.impl; import org.unitils.reflectionassert.ReflectionComparator; import org.unitils.reflectionassert.comparator.Comparator; import org.unitils.reflectionassert.difference.Difference; import org.unitils.reflectionassert.difference.ObjectDifference; import static org.unitils.reflectionassert.util.HibernateUtil.*; /** * Comparator that can handle Hibernate proxies. * <p/> * Special thanks to Tim Peeters for helping us with the implementation. * * @author Tim Ducheyne * @author Filip Neven * @author Tim Peeters */ public class HibernateProxyComparator implements Comparator { /** * Returns true if one or both of the objects is a Hibernate proxy. * * @param left The left object * @param right The right object * @return True if one is a proxy */ public boolean canCompare(Object left, Object right) { return isHibernateProxy(left) || isHibernateProxy(right); } /** * Compares the given objects. If one of the objects is a proxy, the proxy is initialized and the wrapped values * are compared. If both objects are proxies and both objects are not yet loaded (initialized) only the idendtifiers * are compared. This avoids unitils performing unnecessary loads from the database (potentially retrieving a huge * amount of data). If the ids of the proxies are identical, the objects are considered identical, if not the * objects are considered different. * * @param left The left object, not null * @param right The right object, not null * @param onlyFirstDifference True if only the first difference should be returned * @param reflectionComparator The root comparator for inner comparisons, not null * @return A ObjectDifference or null if both maps are equal */ public Difference compare(Object left, Object right, boolean onlyFirstDifference, ReflectionComparator reflectionComparator) { if (isUninitialized(left) && isUninitialized(right)) { String leftType = getEntitiyName(left); String rightType = getEntitiyName(right); if (leftType == null || !leftType.equals(rightType)) { return new ObjectDifference("Different hibernate proxy types. Left: " + leftType + ", right: " + rightType, left, right); } Object leftIndentifier = getIdentifier(left); Object rightIdentifier = getIdentifier(right); Difference identifierDifference = reflectionComparator.getDifference(leftIndentifier, rightIdentifier, onlyFirstDifference); if (identifierDifference != null) { ObjectDifference difference = new ObjectDifference("Different hibernate proxy values", left, right); difference.addFieldDifference("<proxy id>", identifierDifference); return difference; } return null; } // get the actual value if the value is wrapped by a Hibernate proxy Object leftUnproxied = getUnproxiedValue(left); Object rightUnproxied = getUnproxiedValue(right); return reflectionComparator.getDifference(leftUnproxied, rightUnproxied, onlyFirstDifference); } }