blob: 67d346a9eaa1344d382ee8c792d6004da94c3023 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* 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 com.google.gwt.editor.client;
import com.google.gwt.core.client.impl.WeakMapping;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Utility methods for working with AutoBeans.
*/
public final class AutoBeanUtils {
/**
* Returns a map of properties that differ between two AutoBeans. The keys are
* property names and the values are the value of the property in
* <code>b</code>. Properties present in <code>a</code> but missing in
* <code>b</code> will be represented by <code>null</code> values. This
* implementation will compare AutoBeans of different parameterizations,
* although the diff produced is likely meaningless.
* <p>
* This will work for both simple and wrapper AutoBeans.
*/
public static Map<String, Object> diff(AutoBean<?> a, AutoBean<?> b) {
// Fast check for comparing an object to itself
if (a.equals(b)) {
return Collections.emptyMap();
}
final Map<String, Object> toReturn = getAllProperties(b);
// Remove the entries that are equal, adding nulls for missing properties
a.accept(new AutoBeanVisitor() {
@Override
public boolean visitReferenceProperty(String propertyName,
AutoBean<?> previousValue, PropertyContext ctx) {
if (toReturn.containsKey(propertyName)) {
if (equal(propertyName, previousValue)) {
// No change
toReturn.remove(propertyName);
}
} else {
// The predecessor has a value that this object doesn't.
toReturn.put(propertyName, null);
}
return false;
}
@Override
public boolean visitValueProperty(String propertyName,
Object previousValue, PropertyContext ctx) {
if (toReturn.containsKey(propertyName)) {
if (equal(propertyName, previousValue)) {
// No change
toReturn.remove(propertyName);
}
} else {
// The predecessor has a value that this object doesn't.
toReturn.put(propertyName, null);
}
return false;
}
private boolean equal(String propertyName, AutoBean<?> previousValue) {
return previousValue == null && toReturn.get(propertyName) == null
|| previousValue != null && equal(propertyName, previousValue.as());
}
private boolean equal(String propertyName, Object previousValue) {
return previousValue == null && toReturn.get(propertyName) == null
|| previousValue != null
&& previousValue.equals(toReturn.get(propertyName));
}
});
return toReturn;
}
/**
* Returns a map that is a copy of the properties contained in an AutoBean.
* The returned map is mutable, but editing it will not have any effect on the
* bean that produced it.
*/
public static Map<String, Object> getAllProperties(AutoBean<?> bean) {
final Map<String, Object> toReturn = new LinkedHashMap<String, Object>();
// Look at the previous value of all properties
bean.accept(new AutoBeanVisitor() {
@Override
public boolean visitReferenceProperty(String propertyName,
AutoBean<?> value, PropertyContext ctx) {
toReturn.put(propertyName, value == null ? null : value.as());
return false;
}
@Override
public boolean visitValueProperty(String propertyName, Object value,
PropertyContext ctx) {
toReturn.put(propertyName, value);
return false;
}
});
return toReturn;
}
/**
* Return the single AutoBean wrapper that is observing the delegate object or
* <code>null</code> if the parameter is <code>null</code> or not wrapped by
* an AutoBean.
*/
@SuppressWarnings("unchecked")
public static <T, U extends T> AutoBean<T> getAutoBean(U delegate) {
return delegate == null ? null : (AutoBean<T>) WeakMapping.get(delegate,
AutoBean.class.getName());
}
/**
* Utility class.
*/
private AutoBeanUtils() {
}
}