Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/main/java/de/danielbechler/diff/BeanDiffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ public final Node compare(final Node parentNode, final Instances instances)
{
beanNode.setState(Node.State.IGNORED);
}
else if (nodeInspector.isWithMethodEquals(beanNode)){
String method = nodeInspector.getWithMethodEqualsMethod(beanNode);
if (instances.areMethodResultEqual(method))
{
beanNode.setState(Node.State.UNTOUCHED);
}
else
{
beanNode.setState(Node.State.CHANGED);
}
}
else if (instances.areNull() || instances.areSame())
{
beanNode.setState(Node.State.UNTOUCHED);
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/de/danielbechler/diff/CollectionDiffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ else if (nodeInspector.isEqualsOnly(collectionNode))
collectionNode.setState(Node.State.CHANGED);
}
}
else if (nodeInspector.isWithMethodEquals(collectionNode)){
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isWithMethodEquals sounds a little strange. How about hasAlternativeEqualsMethod?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is checking equality of the result of the method, so
"isWithMethodResultEqual" is more explicit, if a little verbose.
Your call, I suppose!
On 25 Jul 2013 21:10, "Daniel Bechler" notifications@github.com wrote:

In src/main/java/de/danielbechler/diff/CollectionDiffer.java:

@@ -61,6 +61,17 @@ else if (nodeInspector.isEqualsOnly(collectionNode))
collectionNode.setState(Node.State.CHANGED);
}
}

  •  else if (nodeInspector.isWithMethodEquals(collectionNode)){ 

isWithMethodEquals sounds a little strange. How about
hasAlternativeEqualsMethod?


Reply to this email directly or view it on GitHubhttps://github.com//pull/69/files#r5408527
.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, now I see. I'm still not sold on isWithMethodResultEqual though. Even with the context I had, I failed to see what it does by just reading the name. But I think we should rather look for a better name in the Configuration, as it will dictate the names in the remaining places.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.
How about "isComparedByMethodResult"?
I think this is a little clearer. I will let you know if I think of
something better!
On 25 Jul 2013 21:38, "Daniel Bechler" notifications@github.com wrote:

In src/main/java/de/danielbechler/diff/CollectionDiffer.java:

@@ -61,6 +61,17 @@ else if (nodeInspector.isEqualsOnly(collectionNode))
collectionNode.setState(Node.State.CHANGED);
}
}

  •  else if (nodeInspector.isWithMethodEquals(collectionNode)){ 

Ah, yes, now I see. I'm still not sold on isWithMethodResultEqual though.
Even with the context I had, I failed to see what it does by just reading
the name. But I think we should rather look for a better name in the
Configuration, as it will dictate the names in the remaining places.


Reply to this email directly or view it on GitHubhttps://github.com//pull/69/files#r5409210
.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better, but still not as descriptive, as I'd like. How about hasEqualsOnlyValueProviderMethod, given we're using equalsOnlyValueProviderMethod in the Configuration?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea cool, is more specific. Gotta stay consistent too. Sounds good.
On 25 Jul 2013 21:56, "Daniel Bechler" notifications@github.com wrote:

In src/main/java/de/danielbechler/diff/CollectionDiffer.java:

@@ -61,6 +61,17 @@ else if (nodeInspector.isEqualsOnly(collectionNode))
collectionNode.setState(Node.State.CHANGED);
}
}

  •  else if (nodeInspector.isWithMethodEquals(collectionNode)){ 

Much better, but still not as descriptive, as I'd like. How about
hasEqualsOnlyValueProviderMethod, given we're using
equalsOnlyValueProviderMethod in the Configuration?


Reply to this email directly or view it on GitHubhttps://github.com//pull/69/files#r5409765
.

String method = nodeInspector.getWithMethodEqualsMethod(collectionNode);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd generally prefer alternativeEqualsMethod instead of methodEquals. Seems a little bit more self explanatory.

if (collectionInstances.areMethodResultEqual(method))
{
collectionNode.setState(Node.State.UNTOUCHED);
}
else
{
collectionNode.setState(Node.State.CHANGED);
}
}
else if (collectionInstances.hasBeenAdded())
{
compareItems(collectionNode, collectionInstances, collectionInstances.getWorking(Collection.class));
Expand Down
68 changes: 66 additions & 2 deletions src/main/java/de/danielbechler/diff/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ 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<PropertyPathAndMethod> methodEqualProperties = new LinkedHashSet<PropertyPathAndMethod>(10);
private final Collection<Class<?>> compareToOnlyTypes = new LinkedHashSet<Class<?>>(10);
private final Collection<Class<?>> equalsOnlyTypes = new LinkedHashSet<Class<?>>(10);
private final Collection<ClassAndMethod> methodEqualTypes = new LinkedHashSet<ClassAndMethod>(10);
private boolean returnUnchangedNodes = false;
private boolean returnIgnoredNodes = false;
private boolean returnCircularNodes = true;
Expand Down Expand Up @@ -124,7 +126,7 @@ public Configuration withoutProperty(final PropertyPath propertyPath)
this.excludedProperties.add(propertyPath);
return this;
}

public Configuration withCompareToOnlyType(final Class<?> type)
{
this.compareToOnlyTypes.add(type);
Expand All @@ -143,12 +145,22 @@ public Configuration withEqualsOnlyProperty(final PropertyPath propertyPath)
return this;
}

public Configuration withMethodEqualsProperty(final PropertyPath propertyPath, final String methodName) {
this.methodEqualProperties.add(new PropertyPathAndMethod(propertyPath, methodName));
return this;
}

public Configuration withMethodEqualsProperty(PropertyPathAndMethod propertyPathEqualsMethod) {
this.methodEqualProperties.add(propertyPathEqualsMethod);
return this;
}

public Configuration withIgnoredNodes()
{
this.returnIgnoredNodes = true;
return this;
}

public Configuration withoutIgnoredNodes()
{
this.returnIgnoredNodes = false;
Expand Down Expand Up @@ -309,6 +321,57 @@ public boolean isEqualsOnly(final Node node)
}
return false;
}

public boolean isWithMethodEquals(Node node){
return getWithMethodEqualsMethod(node) != null;
}

public String getWithMethodEqualsMethod(Node node){
final Class<?> propertyType = node.getType();
if (propertyType != null)
{
ObjectDiffMethodEqualsType annotation = propertyType.getAnnotation(ObjectDiffMethodEqualsType.class);
if (annotation != null)
{
return annotation.method();
}

ClassAndMethod applicable = findMethodEqualPropertyForClass(propertyType);
if (applicable != null)
{
return applicable.getMethod();
}
}
if (node.isWithMethodEquals())
{
return node.getWithMethodEqualsMethod();
}
PropertyPathAndMethod applicable = findMethodEqualPropertyForPath(node.getPropertyPath());
if (applicable != null)
{
return applicable.getMethod();
}
return null;
}

private ClassAndMethod findMethodEqualPropertyForClass(Class<?> clazz){
for(ClassAndMethod propertyPathEqualsMethod: methodEqualTypes){
if(clazz.equals(propertyPathEqualsMethod.getClazz())){
return propertyPathEqualsMethod;
}
}
return null;

}

private PropertyPathAndMethod findMethodEqualPropertyForPath(PropertyPath propertyPath){
for(PropertyPathAndMethod propertyPathEqualsMethod: methodEqualProperties){
if(propertyPath.equals(propertyPathEqualsMethod.getPropertyPath())){
return propertyPathEqualsMethod;
}
}
return null;
}

public boolean isReturnable(final Node node)
{
Expand Down Expand Up @@ -347,4 +410,5 @@ else if (node.isRemoved())
}
return true;
}

}
14 changes: 14 additions & 0 deletions src/main/java/de/danielbechler/diff/Instances.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,19 @@ public boolean areEqual()
{
return isEqual(base, working);
}

public boolean areMethodResultEqual(String method) {
try {
Object baseMethodResult = base.getClass().getMethod(method).invoke(base);
Object workingMethodResult = working.getClass().getMethod(method).invoke(working);
if(baseMethodResult == null){
return workingMethodResult == null;
}
return baseMethodResult.equals(workingMethodResult);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public boolean areEqualByComparison()
{
Expand Down Expand Up @@ -281,4 +294,5 @@ public PropertyPath getPropertyPath(final Node parentNode)
return PropertyPath.createBuilder().withRoot().build();
}
}

}
11 changes: 11 additions & 0 deletions src/main/java/de/danielbechler/diff/MapDiffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ else if (nodeInspector.isEqualsOnly(mapNode))
mapNode.setState(Node.State.CHANGED);
}
}
else if (nodeInspector.isWithMethodEquals(mapNode)){
String method = nodeInspector.getWithMethodEqualsMethod(mapNode);
if (instances.areMethodResultEqual(method))
{
mapNode.setState(Node.State.UNTOUCHED);
}
else
{
mapNode.setState(Node.State.CHANGED);
}
}
else if (instances.hasBeenAdded())
{
compareEntries(mapNode, instances, instances.getWorking(Map.class).keySet());
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/de/danielbechler/diff/NodeInspector.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ interface NodeInspector
boolean isCompareToOnly(Node node);

boolean isEqualsOnly(Node node);

boolean isWithMethodEquals(Node node);
String getWithMethodEqualsMethod(Node node);

boolean isReturnable(Node node);

Expand Down
13 changes: 13 additions & 0 deletions src/main/java/de/danielbechler/diff/accessor/AbstractAccessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public abstract class AbstractAccessor implements Accessor
private Set<String> categories = new TreeSet<String>();
private boolean equalsOnly;
private boolean ignored;
private String withMethodEqualsMethod;

public final Set<String> getCategories()
{
Expand Down Expand Up @@ -54,5 +55,17 @@ public void setIgnored(final boolean ignored)
{
this.ignored = ignored;
}

public boolean isWithMethodEquals(){
return this.withMethodEqualsMethod != null && !this.withMethodEqualsMethod.equals("");
}

public void setWithMethodEqualsMethod(String withMethodEqualsMethod) {
this.withMethodEqualsMethod = withMethodEqualsMethod;
}

public String getWithMethodEqualsMethod(){
return withMethodEqualsMethod;
}

}
1 change: 1 addition & 0 deletions src/main/java/de/danielbechler/diff/accessor/Accessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ public interface Accessor extends PropertyDescriptor
void set(Object target, Object value);

void unset(Object target);

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@ public interface PropertyDescriptor
boolean isIgnored();

boolean isEqualsOnly();


boolean isWithMethodEquals();

String getWithMethodEqualsMethod();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.danielbechler.diff.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@ObjectDiffAnnotation
public @interface ObjectDiffMethodEqualsType {
public String method();
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@
* @return The categories for this property.
*/
public String[] categories() default {};

public String methodEqual() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package de.danielbechler.diff.example;

import java.util.ArrayList;
import java.util.List;

import de.danielbechler.diff.Configuration;
import de.danielbechler.diff.ObjectDifferFactory;
import de.danielbechler.diff.annotation.ObjectDiffMethodEqualsType;
import de.danielbechler.diff.annotation.ObjectDiffProperty;
import de.danielbechler.diff.node.Node;
import de.danielbechler.diff.path.PropertyPath;
import de.danielbechler.diff.visitor.PrintingVisitor;

class MethodEqualExample {
private MethodEqualExample()
{
}

public static void main(final String[] args)
{
PropertyClass prop = new PropertyClass("1", "2");
final EncompassingClass base = new EncompassingClass(prop);
PropertyClass prop2 = new PropertyClass("1", "3");
final EncompassingClass working = new EncompassingClass(prop2);

final Configuration configuration = new Configuration();

// (Option 1) Causes the ObjectDiffer to compare using the method "getProp1" on the 'prop' property of the root object
configuration.withMethodEqualsProperty(PropertyPath.buildWith("prop"), "getProp1");

final Node node = ObjectDifferFactory.getInstance(configuration).compare(working, base);

node.visit(new PrintingVisitor(working, base));

// Output with ignore:
// Property at path '/' has not changed
// Output without ignore:
// Property at path '/prop/prop2' has changed from [ 2 ] to [ 3 ]
}

public static class EncompassingClass
{
private final PropertyClass prop;

public EncompassingClass(final PropertyClass prop)
{
this.prop = prop;
}

/* (Option 2) This annotation causes the ObjectDiffer to use getProp1 method to compare */
//@ObjectDiffProperty(methodEqual = "getProp1")
public PropertyClass getProp() {
return prop;
}
}

/* (Option 3) This annotation causes the ObjectDiffer to use getProp1 method to compare */
//@ObjectDiffMethodEqualsType(method="getProp1")
public static class PropertyClass
{
private String prop1;
private String prop2;

public PropertyClass(String prop1, String prop2)
{
this.prop1 = prop1;
this.prop2 = prop2;
}
public String getProp1() {
return prop1;
}
public String getProp2() {
return prop2;
}
}

}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great example! I like it.

Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ private static void handleObjectDiffPropertyAnnotation(final Method readMethod,
propertyAccessor.setEqualsOnly(annotation.equalsOnly());
propertyAccessor.setIgnored(annotation.ignore());
propertyAccessor.setCategories(Collections.setOf(annotation.categories()));
propertyAccessor.setWithMethodEqualsMethod(annotation.methodEqual());
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/main/java/de/danielbechler/diff/node/DefaultNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ public final boolean isIgnored()
{
return state == State.IGNORED || accessor.isIgnored();
}

public boolean isWithMethodEquals() {
return accessor.isWithMethodEquals();
}

public String getWithMethodEqualsMethod() {
return accessor.getWithMethodEqualsMethod();
}

public final Set<String> getCategories()
{
Expand Down Expand Up @@ -474,4 +482,5 @@ public void setCircleStartNode(final Node circleStartNode)
{
this.circleStartNode = circleStartNode;
}

}
4 changes: 4 additions & 0 deletions src/main/java/de/danielbechler/diff/node/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,8 @@ public enum State

<T extends Annotation> T getPropertyAnnotation(Class<T> annotationClass);

boolean isWithMethodEquals();

String getWithMethodEqualsMethod();

}
16 changes: 16 additions & 0 deletions src/main/java/de/danielbechler/diff/path/ClassAndMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.danielbechler.diff.path;

public class ClassAndMethod {
private Class<?> clazz;
private String method;
public ClassAndMethod(Class<?> clazz, String method){
this.clazz = clazz;
this.method = method;
}
public Class<?> getClazz() {
return clazz;
}
public String getMethod() {
return method;
}
}
Loading