8

I am writing a validator which needs to test if a spring form object has changed.

In the validator if no changes have been made to the form, an error should be displayed.

Is there a spring mechanism to do this?

This is because a very expensive webservice update call is made when I submit, and I need to prevent the webservice call from being made if no changes have been made.

Cheers.

Samuel Parsonage
  • 3,077
  • 1
  • 18
  • 21
Mitch
  • 81
  • 1
  • 2
  • Are you refer to JSR 303 Validator, or Spring Validator (org.springframework.validation.Validator)? – Ralph Apr 20 '11 at 07:27
  • Mitch is in my team, he's referring to the Spring Validator. – Samuel Parsonage Apr 20 '11 at 23:17
  • Something like this: Bind the object to the form, at the point of binding, take a copy or hash of all fields. To validate, compare copy to fields or take fresh hash of all fields, give error if fields/hash is the same. – Ben Apr 21 '11 at 11:53

3 Answers3

2

I'm not aware of any built-in Spring mechanism to handle this. I'd save a copy of the original object, and the modified object. I'd override the Form.equals() method appropriately (possibly delegating to org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(), if all of the fields are primitives/strings) and use Form.equals() to check whether the form had changed.

I have seen two distinct responses here which imply that overriding the "hashCode" method is a good way to go. It is not in the contract of hashCode() to guarantee inequality, this could lead to problems. Be sure to override equals() as well. Of course it's a one in a trillion chance of a hash collision, but it's poor design to rely on hashCode() alone when you're trying to check if two objects are different.

piepera
  • 2,033
  • 1
  • 20
  • 21
  • Good point. A better way is probably to store the original object in the session and either test for equality if your equals() method gives you that information or to write a separate method to compare specific field changes. – climmunk May 25 '12 at 19:29
1

Override your hashCode() function to ensure a different value is returned when form values change. Save the return value of the function and test to see whether it's changed.

public class Person {
  String first;
  String last;
  int prevHash;
  @Override
  public int hashCode() {
    // does not include the value of currHash
    String stringHash = String.format("%1$-29s%2$-29s", first,last);
    return stringHash.hashCode();
  }
}

public class PersonValidator  implements Validator {
  public void validate(Object obj, Errors e) {
    Person p = (Person) obj;
    if (p.hashCode() == p.getPrevHash()) {
      e.reject("person", "unchanged");
    } 
  }
  ...
}

I don't think there's a Spring-provided validation test to check whether a form backing object has changed

Note that you could perform additional tests on the client side before allowing the user to submit the form.

climmunk
  • 1,141
  • 1
  • 12
  • 29
0

Try different approach based on client-side checking if form has changed. Starting form user interface / jQuery:

   $(document).ready(function() {
        var isFormChanged = false;
        var isConfirmed = false;
        $("form :input").change(function() {
            console.log($(this).attr('name'));
            isFormChanged = true;
        });

        $("#storeForm").submit(function(event) {
            if (!isConfirmed) {
                event.preventDefault();
            }
            if (isFormChanged) {
                console.log("Form has changed");
                $(":submit").addClass("btn-danger");
                $(":submit").text("Confirm");
                isConfirmed = true;
            }
        });
    });

You can also make hidden field in the form to send back information to Spring to check all of those once again on server-side. It is faster than pushing back all form data to server just to check if something has changed every time.