Skip to content

Features/use comparator #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 6, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/main/java/de/danielbechler/diff/BeanDiffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,18 @@ else if (instances.hasBeenRemoved())

private void compareUsingAppropriateMethod(final Node beanNode, final Instances instances)
{
if (nodeInspector.isIntrospectible(beanNode))
if (nodeInspector.isCompareToOnly(beanNode))
{
compareUsingIntrospection(beanNode, instances);
compareUsingCompareTo(beanNode, instances);
}
else if (nodeInspector.isEqualsOnly(beanNode))
{
compareUsingEquals(beanNode, instances);
}
else if (nodeInspector.isIntrospectible(beanNode))
{
compareUsingIntrospection(beanNode, instances);
}
}

private void compareUsingIntrospection(final Node beanNode, final Instances beanInstances)
Expand All @@ -96,6 +100,19 @@ private void compareUsingIntrospection(final Node beanNode, final Instances bean
}
}

@SuppressWarnings({"MethodMayBeStatic"})
private void compareUsingCompareTo(final Node beanNode, final Instances instances)
{
if (instances.areEqualByComparison())
{
beanNode.setState(Node.State.UNTOUCHED);
}
else
{
beanNode.setState(Node.State.CHANGED);
}
}

@SuppressWarnings({"MethodMayBeStatic"})
private void compareUsingEquals(final Node beanNode, final Instances instances)
{
Expand Down
32 changes: 26 additions & 6 deletions src/main/java/de/danielbechler/diff/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public enum PrimitiveDefaultValueMode
private final Collection<PropertyPath> includedProperties = new HashSet<PropertyPath>(10);
private final Collection<PropertyPath> excludedProperties = new HashSet<PropertyPath>(10);
private final Collection<PropertyPath> equalsOnlyProperties = new LinkedHashSet<PropertyPath>(10);
private final Collection<Class<?>> compareToOnlyTypes = new LinkedHashSet<Class<?>>(10);
private final Collection<Class<?>> equalsOnlyTypes = new LinkedHashSet<Class<?>>(10);
private boolean returnUnchangedNodes = false;
private boolean returnIgnoredNodes = false;
Expand Down Expand Up @@ -124,6 +125,12 @@ public Configuration withoutProperty(final PropertyPath propertyPath)
return this;
}

public Configuration withCompareToOnlyType(final Class<?> type)
{
this.compareToOnlyTypes.add(type);
return this;
}

public Configuration withEqualsOnlyType(final Class<?> type)
{
this.equalsOnlyTypes.add(type);
Expand Down Expand Up @@ -257,6 +264,23 @@ public boolean isExcluded(final Node node)
return false;
}

public boolean isCompareToOnly(final Node node)
{
final Class<?> propertyType = node.getType();
if (propertyType != null)
{
if (compareToOnlyTypes.contains(propertyType) && Comparable.class.isAssignableFrom(propertyType))
{
return true;
}
if (Classes.isComparableType(propertyType))
{
return true;
}
}
return false;
}

public boolean isEqualsOnly(final Node node)
{
final Class<?> propertyType = node.getType();
Expand Down Expand Up @@ -311,13 +335,9 @@ else if (node.hasChildren())
return true;
}

public boolean isIntrospectible(final Node node)
public boolean isIntrospectible(final Node node)
{
if (isEqualsOnly(node))
{
return false;
}
else if (node.isAdded())
if (node.isAdded())
{
return returnChildrenOfAddedNodes;
}
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/de/danielbechler/diff/Instances.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.*;

import static de.danielbechler.util.Objects.*;
import static de.danielbechler.util.Comparables.*;

/** @author Daniel Bechler */
@SuppressWarnings({"UnusedDeclaration"})
Expand Down Expand Up @@ -172,7 +173,12 @@ public boolean areEqual()
return isEqual(base, working);
}

public boolean areSame()
public boolean areEqualByComparison()
{
return isEqualByComparison((Comparable) base, (Comparable) working);
}

public boolean areSame()
{
return working == base;
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/de/danielbechler/diff/NodeInspector.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ interface NodeInspector

boolean isExcluded(Node node);

boolean isCompareToOnly(Node node);

boolean isEqualsOnly(Node node);

boolean isReturnable(Node node);
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/de/danielbechler/util/Classes.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.slf4j.*;

import java.lang.reflect.*;
import java.math.BigDecimal;
import java.net.*;
import java.util.*;

Expand Down Expand Up @@ -98,6 +99,11 @@ public static boolean isSimpleType(final Class<?> clazz)
Class.class.equals(clazz);
}

public static boolean isComparableType(final Class<?> clazz)
{
return BigDecimal.class.equals(clazz);
}

public static <T> T freshInstanceOf(final Class<T> clazz)
{
if (clazz == null)
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/de/danielbechler/util/Comparables.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2012 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.util;

/** @author Daniel Bechler */
public class Comparables
{
private Comparables()
{
}

public static <T extends Comparable<T>> boolean isEqualByComparison(final T a, final T b)
{
if (a != null)
{
return a.compareTo(b) == 0;
}
else if (b != null)
{
return b.compareTo(a) == 0;
}
return true;
}
}
12 changes: 12 additions & 0 deletions src/test/java/de/danielbechler/diff/BeanDifferShould.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ public void ignore_ignored_properties()
assertThat(node).self().hasState(Node.State.IGNORED);
}

@Test
public void compare_bean_via_compare_to()
{
final ObjectWithCompareTo working = new ObjectWithCompareTo("foo", "ignore");
final ObjectWithCompareTo base = new ObjectWithCompareTo("foo", "ignore this too");
configuration.withCompareToOnlyType(ObjectWithCompareTo.class);

final Node node = differ.compare(Node.ROOT, Instances.of(working, base));

assertThat(node).self().isUntouched();
}

@Test
public void compare_bean_via_equals()
{
Expand Down
40 changes: 32 additions & 8 deletions src/test/java/de/danielbechler/diff/ConfigurationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.mockito.stubbing.*;
import org.testng.annotations.*;

import java.math.BigDecimal;

import static org.fest.assertions.api.Assertions.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.*;
Expand Down Expand Up @@ -98,6 +100,35 @@ public void testIsIgnoredWithCategory() throws Exception
assertThat(configuration.isIgnored(node), is(true));
}

@SuppressWarnings({"unchecked"})
@Test
public void testIsCompareToOnlyWithConfiguredPropertyType() throws Exception
{
final Class aClass = ObjectWithStringAndCompareTo.class;
when(node.getType()).thenReturn(aClass);
configuration.withCompareToOnlyType(aClass);
assertThat(configuration.isCompareToOnly(node), is(true));
}

@SuppressWarnings({"unchecked"})
@Test
public void testIsCompareToOnlyWithConfiguredPropertyTypeNotComparable() throws Exception
{
final Class aClass = ObjectWithString.class;
when(node.getType()).thenReturn(aClass);
configuration.withCompareToOnlyType(aClass);
assertThat(configuration.isCompareToOnly(node), is(false));
}

@SuppressWarnings({"unchecked"})
@Test
public void testIsCompareToOnlyWithComparableType() throws Exception
{
final Class aClass = BigDecimal.class;
when(node.getType()).thenReturn(aClass);
assertThat(configuration.isCompareToOnly(node), is(true));
}

@Test
public void testIsEqualsOnlyWithConfiguredPropertyPath() throws Exception
{
Expand Down Expand Up @@ -142,13 +173,6 @@ public void testIsEqualsOnlyWithTypeThatShouldNotBeComparedUsingEquals() throws
assertThat(configuration.isEqualsOnly(node), is(false));
}

@Test
public void testIsIntrospectibleWithEqualsOnlyNodeReturnsFalse()
{
when(node.getType()).then(returnClass(String.class));
assertThat(configuration.isIntrospectible(node)).isFalse();
}

@Test
public void testIsIntrospectibleWithUntouchedNonEqualsOnlyNodeReturnsFalse()
{
Expand Down Expand Up @@ -189,7 +213,7 @@ public void testIsIntrospectibleReturnsFalseForRemovedNodeIfChildrenOfRemovedNod
assertThat(configuration.isIntrospectible(node)).isFalse();
}

@SuppressWarnings({"TypeMayBeWeakened"})
@SuppressWarnings({"TypeMayBeWeakened"})
private static <T> Answer<Class<T>> returnClass(final Class<T> aClass)
{
return new Answer<Class<T>>()
Expand Down
70 changes: 70 additions & 0 deletions src/test/java/de/danielbechler/diff/mock/ObjectWithCompareTo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2012 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.mock;

import de.danielbechler.util.Assert;

/** @author Daniel Bechler */
public class ObjectWithCompareTo implements Comparable<ObjectWithCompareTo>
{
private final String key;

private String value;
private ObjectWithCompareTo item;

public ObjectWithCompareTo(final String key)
{
Assert.hasText(key, "key");
this.key = key;
}

public ObjectWithCompareTo(final String key, final String value)
{
this(key);
this.value = value;
}

public String getKey()
{
return key;
}

public String getValue()
{
return value;
}

public void setValue(final String value)
{
this.value = value;
}

public ObjectWithCompareTo getItem()
{
return item;
}

public ObjectWithCompareTo setItem(final ObjectWithCompareTo item)
{
this.item = item;
return this;
}

public int compareTo(ObjectWithCompareTo objectWithCompareTo) {
return this.key.compareTo(objectWithCompareTo.key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2012 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.mock;

/** @author Daniel Bechler */
@SuppressWarnings({
"UnusedDeclaration"
})
public class ObjectWithStringAndCompareTo implements Comparable<ObjectWithStringAndCompareTo>
{
private String value;

public ObjectWithStringAndCompareTo()
{
}

public ObjectWithStringAndCompareTo(final String value)
{
this.value = value;
}

public String getValue()
{
return value;
}

public void setValue(final String value)
{
this.value = value;
}

public int compareTo(ObjectWithStringAndCompareTo objectWithStringAndCompareTo) {
return this.value.compareTo(objectWithStringAndCompareTo.value);
}
}