001    /**
002     * Copyright 2002-2005 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.binding.value.support;
017    
018    import java.math.BigDecimal;
019    import java.math.BigInteger;
020    import java.util.Arrays;
021    import java.util.Calendar;
022    import java.util.Collection;
023    import java.util.Date;
024    import java.util.HashSet;
025    import java.util.List;
026    import java.util.Set;
027    
028    import org.springframework.binding.value.ValueChangeDetector;
029    
030    /**
031     * Implementation of ValueChangeDetector that maintains a set of classes for which it is
032     * "safe" to use <code>equals()</code> for detecting a change in value (those classes
033     * that have immutable values). For all objects of a type in this set, the value
034     * comparison will be done using equals. For all other types, object equivalence (the ==
035     * operator) will be used.
036     * <p>
037     * This is the default value change detector handed out by the Application Services.
038     *
039     * @author Larry Streepy
040     *
041     */
042    public class DefaultValueChangeDetector implements ValueChangeDetector {
043    
044        /*
045         * All the classes that are known to have a safe implementation of equals.
046         */
047        protected final Set classesWithSafeEquals = new HashSet( Arrays.asList( new Class[] { Boolean.class, Byte.class,
048                Short.class, Integer.class, Long.class, Float.class, Double.class, String.class, Character.class,
049                BigDecimal.class, BigInteger.class, Date.class, Calendar.class } ) );
050    
051        /**
052         * Determines if there has been a change in value between the provided arguments. As
053         * many objects do not implement #equals in a manner that is strict enough for the
054         * requirements of this class, difference is determined using <code>!=</code>,
055         * however, to improve accuracy #equals will be used when this is definitely safe e.g.
056         * for Strings, Booleans, Numbers, Dates.
057         *
058         * @param oldValue Original object value
059         * @param newValue New object value
060         * @return true if the objects are different enough to indicate a change in the value
061         *         model
062         */
063        public boolean hasValueChanged(Object oldValue, Object newValue) {
064            if( oldValue != null && classesWithSafeEquals.contains( oldValue.getClass() ) )
065                return !oldValue.equals( newValue );
066    
067            return oldValue != newValue;
068        }
069    
070        /**
071         * Specify the set of classes that have an equals method that is safe to use for
072         * determining a value change.
073         *
074         * @param classes with safe equals methods
075         */
076        public void setClassesWithSafeEquals(Collection classes) {
077            classesWithSafeEquals.clear();
078            classesWithSafeEquals.addAll( classes );
079        }
080    
081        /**
082         * Get the set of classes that have an equals method that is safe to use for
083         * determining a value change.
084         * @return Collection of classes with safe equals methods
085         */
086        public Collection getClassesWithSafeEquals() {
087            return classesWithSafeEquals;
088        }
089    }