Announcement Announcement Module
Collapse
No announcement yet.
Integer Constraints in RulesSource? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Integer Constraints in RulesSource?

    I experiment with making RulesSource similar to PetClinicValidationRulesSource. In PetClinicValidationRulesSource, all Constraints are based on String properties in domain objects. I cannot find any example for other property types like Integer. Example, how can I do each of the following for Integer properties (assume each is an independent constraint...that is, don't combine them in your reply please)?

    1) required and must be positive Integer
    2) required and must be Integer between -180 and 180
    3) required and must be Integer greater than 100
    4) required and must be Integer in set (1, 3, 5, 7)
    5) NOT required but if filled in it must be between 5 and 10

    Please forgiving me if I miss something in Petclinic or in docs!

  • #2
    Code:
            Rules integerRules = new Rules(TestBean.class) {
                protected void initRules() {
                    add("number1", all(new Constraint[] { required(), gt(0) });
                    add("number2", range(-180, 180));
                    add("number3", all(new Constraint[] { required(), gt(100) });
                    add("number4", all(new Constraint[] { required(), inGroup(new Object[] { 1, 3, 5 7 });
                    add("number5", if(present(), between(6, 10)));
                }
    
            };
    Pretty slick huh?

    Comment


    • #3
      Originally posted by kdonald
      Pretty slick huh?
      Well, yes, except some compiler error. :cry:

      I fix first four like this:
      Code:
      add("number1", all(new Constraint[] { required(), gt("number1", new Integer(0)) }));
      
      add("number2", inRange("number2", new Integer(-180), new Integer(180)));
      
      add("number3", all(new Constraint[] { required(), gt("number3", new Integer(100)) }));
      
      add("number4", all(new Constraint[] { required(), inGroup(new Object[] {new Integer(1), new Integer(3), new Integer(5), new Integer(7)})}));
      Seems first four correct now with my changes? Main thing is need to make int to Integer.

      But problem is fifth example. First, "if" is Java keyword so can't use like this for method name. Second, present() and between() don't seem to exist in lastest code from CVS. Maybe I look in wrong place but I thinks these two method should be in org.springframework.rules.factory.Constraints class, no? Maybe you not check in yet? Or maybe not coming across in anonymous CVS yet because propagation delay?

      Please suggest help?

      Comment


      • #4
        Steve--um, I haven't yet added those convenience methods to the Constraints factory yet. I should've mentioned!

        Actually, what you're doing is incorrect: you're added a property constraint with a value constraint that is also a property constraint! (I'll put a check in constrants that won't allow that to happen).

        I'm going to add them now ;-)

        Comment


        • #5
          Actually, what you're doing is incorrect: you're added a property constraint with a value constraint that is also a property constraint! (I'll put a check in constrants that won't allow that to happen).
          Hmmn. Please explain?

          Comment


          • #6
            Originally posted by kdonald
            Actually, what you're doing is incorrect: you're added a property constraint with a value constraint that is also a property constraint!
            Maybe you talking about how I added property names to constraint factory methods? For example I changed gt(0) to gt("number1", new Integer(0)) })...I added "number1" parameter here. If I don't add, it does not compiles. I do note that the one parameter version of gt() is actually declared in PropertyConstraints. However, DefaultRulesSource extends Constraints, not PropertyConstraints. So maybe this is the problem? How to fix?

            Comment


            • #7
              Originally posted by steve_smith
              But problem is fifth example. First, "if" is Java keyword so can't use like this for method name.
              Keith -- I concur with Stefano. AFAIK you cannot use "if" as a method name. Perhaps you could call it "iff"...but this might be confusing because "iff" is a common abbreviation for "if and only if" in mathematics. Maybe "if_"?

              Comment


              • #8
                Guys, that was psudo code for convenience methods we should add.

                Yes, if() is invalid.

                I'm going with ifTrue()

                gimme a sec and I'll check it all in!!

                Comment


                • #9
                  Here are the new methods

                  Code:
                  	public Constraint eq(Object value) {
                  		return getConstraints().eq(value);
                  	}
                  
                  	public Constraint eq(int value) {
                  		return getConstraints().eq(value);
                  	}
                  
                  	public Constraint eq(Object value, Comparator comparator) {
                  		return getConstraints().eq(value, comparator);
                  	}
                  
                  	public Constraint gt(Comparable value) {
                  		return getConstraints().gt(value);
                  	}
                  
                  	public Constraint gt(int value) {
                  		return getConstraints().gt(value);
                  	}
                  
                  	public Constraint gt(Comparable value, Comparator comparator) {
                  		return getConstraints().gt(value);
                  	}
                  
                  	public Constraint gte(Comparable value) {
                  		return getConstraints().gte(value);
                  	}
                  
                  	public Constraint gte(int value) {
                  		return getConstraints().gte(value);
                  	}
                  
                  	public Constraint gte(Comparable value, Comparator comparator) {
                  		return getConstraints().gte(value, comparator);
                  	}
                  
                  	public Constraint lt(Comparable value) {
                  		return getConstraints().lt(value);
                  	}
                  
                  	public Constraint lt(int value) {
                  		return getConstraints().lt(value);
                  	}
                  
                  	public Constraint lt(Comparable value, Comparator comparator) {
                  		return getConstraints().lt(value, comparator);
                  	}
                  
                  	public Constraint lte(Comparable value) {
                  		return getConstraints().lte(value);
                  	}
                  
                  	public Constraint lte(int value) {
                  		return getConstraints().lte(value);
                  	}
                  
                  	public Constraint lte(Comparable value, Comparator comparator) {
                  		return getConstraints().lte(value, comparator);
                  	}
                  
                  	public Constraint range(Comparable min, Comparable max) {
                  		return getConstraints().range(min, max);
                  	}
                  
                  	public Constraint range(Object min, Object max, Comparator comparator) {
                  		return getConstraints().range(min, max, comparator);
                  	}
                  
                  	public Constraint range(int min, int max) {
                  		return getConstraints().range(min, max);
                  	}
                  
                  	public Constraint between(Comparable min, Comparable max) {
                  		return getConstraints().between(min, max);
                  	}
                  
                  	public Constraint between(Object min, Object max, Comparator comparator) {
                  		return getConstraints().between(min, max, comparator);
                  	}
                  
                  	public Constraint between(int min, int max) {
                  		return getConstraints().between(min, max);
                  	}
                  
                  	public Constraint present() {
                  		return getConstraints().present();
                  	}
                  
                  	public Constraint ifTrue(Constraint constraint, Constraint mustAlsoBeTrue) {
                  		return getConstraints().ifTrue(constraint, mustAlsoBeTrue);
                  	}
                  
                  	public Constraint ifTrueElse(Constraint constraint, Constraint mustAlsoBeTrue, Constraint elseMustAlsoBeTrue) {
                  		return getConstraints().ifTrue(constraint, mustAlsoBeTrue, elseMustAlsoBeTrue);
                  	}
                  This is ConstraintsAccessor, which Rules, RulesSource and AbstractConstraint extend, for convenience constraints building. It'll be CVS'ed shortly.

                  Comment


                  • #10
                    Okay this is great! Now you allowed to take 15 minute break for Starbucks coffee! Maybe I let you have pumpkin scone too. :lol:

                    Comment


                    • #11
                      While I waiting for CVS propagate to anonymous, I tried adding gt() constraint to Integer property. I made it > 5. If I type 6, no validation error message in dialog message area as expected (good). If I type 5, I see message "<my property> must be greater than 5" as expected (good). Problem is, if I type say "6a", I see cryptic message in dialog message area: "<my property> org.springframework.binding.form.support.Validatin gFormModel". I also see this in log (console): "[INFO,ValidatingFormModel,AWT-EventQueue-0] Illegal argument exception occured setting value"

                      I think to myself, okay Stefano, let's try making regex constraint for only numeric characters. So I try adding this constraint:
                      Code:
                      regexp&#40;"&#91;0-9&#93;*", "numeric"&#41;
                      As can see, is very similar to this regex example from Petclinic:
                      Code:
                      regexp&#40;"&#91;a-zA-Z&#93;*", "alphabetic"&#41;
                      So I think, good this will work. Problem is, when I try to execute dialog, I get ClassCastException in RegexpConstraint.test(). Here is full stack trace, if helps:

                      Code:
                      &#91;ERROR,ApplicationAdvisor,AWT-EventQueue-0&#93; java.lang.reflect.InvocationTargetException
                      java.lang.RuntimeException&#58; java.lang.reflect.InvocationTargetException
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;231&#41;
                      	at org.springframework.rules.reporting.BeanValidationResultsCollector.collectPropertyResultsInternal&#40;BeanValidationResultsCollector.java&#58;73&#41;
                      	at org.springframework.rules.reporting.BeanValidationResultsCollector.collectPropertyResults&#40;BeanValidationResultsCollector.java&#58;67&#41;
                      	at org.springframework.binding.form.support.ValidatingFormModel$ValidatingFormValueModel.validatePropertyConstraint&#40;ValidatingFormModel.java&#58;298&#41;
                      	at org.springframework.binding.form.support.ValidatingFormModel.validate&#40;ValidatingFormModel.java&#58;432&#41;
                      	at org.springframework.richclient.forms.SwingFormModel.validate&#40;SwingFormModel.java&#58;863&#41;
                      	at org.springframework.richclient.dialog.FormBackedDialogPage.createControl&#40;FormBackedDialogPage.java&#58;72&#41;
                      	at org.springframework.richclient.dialog.AbstractDialogPage$1.createControl&#40;AbstractDialogPage.java&#58;49&#41;
                      	at org.springframework.richclient.factory.AbstractControlFactory.getControl&#40;AbstractControlFactory.java&#58;48&#41;
                      	at org.springframework.richclient.dialog.AbstractDialogPage.getControl&#40;AbstractDialogPage.java&#58;215&#41;
                      	at org.springframework.richclient.dialog.TitledPageApplicationDialog.createTitledDialogContentPane&#40;TitledPageApplicationDialog.java&#58;69&#41;
                      	at org.springframework.richclient.dialog.TitledApplicationDialog.createDialogContentPane&#40;TitledApplicationDialog.java&#58;132&#41;
                      	at org.springframework.richclient.dialog.TitledApplicationDialog.addDialogComponents&#40;TitledApplicationDialog.java&#58;121&#41;
                      	at org.springframework.richclient.dialog.ApplicationDialog.createDialog&#40;ApplicationDialog.java&#58;288&#41;
                      	at org.springframework.richclient.dialog.ApplicationDialog.showDialog&#40;ApplicationDialog.java&#58;257&#41;
                      	at stefano.example.ui.MyView$PropertiesCommandExecutor.execute&#40;MyView.java&#58;477&#41;
                      	at org.springframework.richclient.command.support.AbstractActionCommandExecutor.execute&#40;AbstractActionCommandExecutor.java&#58;51&#41;
                      	at org.springframework.richclient.command.TargetableActionCommand.doExecuteCommand&#40;TargetableActionCommand.java&#58;97&#41;
                      	at org.springframework.richclient.command.ActionCommand.execute&#40;ActionCommand.java&#58;188&#41;
                      	at org.springframework.richclient.command.ActionCommand$1.actionPerformed&#40;ActionCommand.java&#58;123&#41;
                      	at javax.swing.AbstractButton.fireActionPerformed&#40;AbstractButton.java&#58;1764&#41;
                      	at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed&#40;AbstractButton.java&#58;1817&#41;
                      	at javax.swing.DefaultButtonModel.fireActionPerformed&#40;DefaultButtonModel.java&#58;419&#41;
                      	at javax.swing.DefaultButtonModel.setPressed&#40;DefaultButtonModel.java&#58;257&#41;
                      	at javax.swing.AbstractButton.doClick&#40;AbstractButton.java&#58;289&#41;
                      	at javax.swing.plaf.basic.BasicMenuItemUI.doClick&#40;BasicMenuItemUI.java&#58;1113&#41;
                      	at javax.swing.plaf.basic.BasicMenuItemUI$MouseInputHandler.mouseReleased&#40;BasicMenuItemUI.java&#58;943&#41;
                      	at java.awt.Component.processMouseEvent&#40;Component.java&#58;5134&#41;
                      	at java.awt.Component.processEvent&#40;Component.java&#58;4931&#41;
                      	at java.awt.Container.processEvent&#40;Container.java&#58;1566&#41;
                      	at java.awt.Component.dispatchEventImpl&#40;Component.java&#58;3639&#41;
                      	at java.awt.Container.dispatchEventImpl&#40;Container.java&#58;1623&#41;
                      	at java.awt.Component.dispatchEvent&#40;Component.java&#58;3480&#41;
                      	at java.awt.LightweightDispatcher.retargetMouseEvent&#40;Container.java&#58;3450&#41;
                      	at java.awt.LightweightDispatcher.processMouseEvent&#40;Container.java&#58;3165&#41;
                      	at java.awt.LightweightDispatcher.dispatchEvent&#40;Container.java&#58;3095&#41;
                      	at java.awt.Container.dispatchEventImpl&#40;Container.java&#58;1609&#41;
                      	at java.awt.Window.dispatchEventImpl&#40;Window.java&#58;1590&#41;
                      	at java.awt.Component.dispatchEvent&#40;Component.java&#58;3480&#41;
                      	at java.awt.EventQueue.dispatchEvent&#40;EventQueue.java&#58;450&#41;
                      	at java.awt.EventDispatchThread.pumpOneEventForHierarchy&#40;EventDispatchThread.java&#58;197&#41;
                      	at java.awt.EventDispatchThread.pumpEventsForHierarchy&#40;EventDispatchThread.java&#58;150&#41;
                      	at java.awt.EventDispatchThread.pumpEvents&#40;EventDispatchThread.java&#58;144&#41;
                      	at java.awt.EventDispatchThread.pumpEvents&#40;EventDispatchThread.java&#58;136&#41;
                      	at java.awt.EventDispatchThread.run&#40;EventDispatchThread.java&#58;99&#41;
                      Caused by&#58; java.lang.reflect.InvocationTargetException
                      	at sun.reflect.NativeMethodAccessorImpl.invoke0&#40;Native Method&#41;
                      	at sun.reflect.NativeMethodAccessorImpl.invoke&#40;NativeMethodAccessorImpl.java&#58;39&#41;
                      	at sun.reflect.DelegatingMethodAccessorImpl.invoke&#40;DelegatingMethodAccessorImpl.java&#58;25&#41;
                      	at java.lang.reflect.Method.invoke&#40;Method.java&#58;324&#41;
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;224&#41;
                      	... 45 more
                      Caused by&#58; java.lang.RuntimeException&#58; java.lang.reflect.InvocationTargetException
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;231&#41;
                      	at org.springframework.rules.reporting.BeanValidationResultsCollector.visit&#40;BeanValidationResultsCollector.java&#58;89&#41;
                      	... 50 more
                      Caused by&#58; java.lang.reflect.InvocationTargetException
                      	at sun.reflect.NativeMethodAccessorImpl.invoke0&#40;Native Method&#41;
                      	at sun.reflect.NativeMethodAccessorImpl.invoke&#40;NativeMethodAccessorImpl.java&#58;39&#41;
                      	at sun.reflect.DelegatingMethodAccessorImpl.invoke&#40;DelegatingMethodAccessorImpl.java&#58;25&#41;
                      	at java.lang.reflect.Method.invoke&#40;Method.java&#58;324&#41;
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;224&#41;
                      	... 51 more
                      Caused by&#58; java.lang.RuntimeException&#58; java.lang.reflect.InvocationTargetException
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;231&#41;
                      	at org.springframework.rules.reporting.ValidationResultsCollector.visit&#40;ValidationResultsCollector.java&#58;90&#41;
                      	... 56 more
                      Caused by&#58; java.lang.reflect.InvocationTargetException
                      	at sun.reflect.NativeMethodAccessorImpl.invoke0&#40;Native Method&#41;
                      	at sun.reflect.NativeMethodAccessorImpl.invoke&#40;NativeMethodAccessorImpl.java&#58;39&#41;
                      	at sun.reflect.DelegatingMethodAccessorImpl.invoke&#40;DelegatingMethodAccessorImpl.java&#58;25&#41;
                      	at java.lang.reflect.Method.invoke&#40;Method.java&#58;324&#41;
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;224&#41;
                      	... 57 more
                      Caused by&#58; java.lang.RuntimeException&#58; java.lang.reflect.InvocationTargetException
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;231&#41;
                      	at org.springframework.rules.reporting.BeanValidationResultsCollector.visit&#40;BeanValidationResultsCollector.java&#58;122&#41;
                      	... 62 more
                      Caused by&#58; java.lang.reflect.InvocationTargetException
                      	at sun.reflect.NativeMethodAccessorImpl.invoke0&#40;Native Method&#41;
                      	at sun.reflect.NativeMethodAccessorImpl.invoke&#40;NativeMethodAccessorImpl.java&#58;39&#41;
                      	at sun.reflect.DelegatingMethodAccessorImpl.invoke&#40;DelegatingMethodAccessorImpl.java&#58;25&#41;
                      	at java.lang.reflect.Method.invoke&#40;Method.java&#58;324&#41;
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;224&#41;
                      	... 63 more
                      Caused by&#58; java.lang.RuntimeException&#58; java.lang.reflect.InvocationTargetException
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;231&#41;
                      	at org.springframework.rules.reporting.ValidationResultsCollector.visit&#40;ValidationResultsCollector.java&#58;90&#41;
                      	... 68 more
                      Caused by&#58; java.lang.reflect.InvocationTargetException
                      	at sun.reflect.GeneratedMethodAccessor23.invoke&#40;Unknown Source&#41;
                      	at sun.reflect.DelegatingMethodAccessorImpl.invoke&#40;DelegatingMethodAccessorImpl.java&#58;25&#41;
                      	at java.lang.reflect.Method.invoke&#40;Method.java&#58;324&#41;
                      	at org.springframework.util.visitor.ReflectiveVisitorSupport.invokeVisit&#40;ReflectiveVisitorSupport.java&#58;224&#41;
                      	... 69 more
                      Caused by&#58; java.lang.ClassCastException
                      	at org.springframework.rules.constraint.RegexpConstraint.test&#40;RegexpConstraint.java&#58;49&#41;
                      	at org.springframework.rules.reporting.ValidationResultsCollector.visit&#40;ValidationResultsCollector.java&#58;161&#41;
                      	at org.springframework.rules.reporting.BeanValidationResultsCollector.visit&#40;BeanValidationResultsCollector.java&#58;126&#41;
                      	... 73 more
                      Indeed, when I use debugger, I inspect "argument" parameter to RegexpConstraint.test() and is Integer but cast is for CharSequence. So that is why ClassCastException, obviously.

                      So, thinking I do something wrong, I try adding my numeric constraint to a String property instead of Integer. In this case, when I type "6a", I see proper message in dialog message area: "<my property> must consist of numeric characters only".

                      So, perhaps regex is only working for String properties right now but maybe it should be changed for supporting other types. If not, please tell how to apply constraints to Integer property that will give nice validation error message in dialog if user tries typing non-numeric character?

                      Comment


                      • #12
                        Well, regexps are designed to work on strings, not ints. A interesting possibility though. Would it make sense to try to convert the int to a string using the String.valueOf() method in the regexp test...

                        The problem is the reporting system needs some work ;-)

                        I'll see about addressing your problem!

                        Comment


                        • #13
                          Originally posted by kdonald
                          Well, regexps are designed to work on strings, not ints.
                          Yes but I guess I thinking that int is String while in JTextField. Maybe regex() constraints should be tried first before you try to convert String in the JTextField to the type of the bound property?

                          Originally posted by kdonald
                          The problem is the reporting system needs some work
                          Oh, you're too humble. You are doing great job really! Keep it up!

                          Comment


                          • #14
                            I'm not really comfortable with trying to apply regexs to numbers... RegExs are great for working with Strings, and they are meant entirely for Strings. There's a seperate set of operations that are appropriate for other kinds of data.

                            The better way to address the specific example you gave is to have a text field that simply only accepts numeric input (via a JFormattedTextField or the like). In fact, when SwingModelForm creates a control for a Numeric property, it should return a text field that only accepts numeric data... (Which I should just write and submit into the code instead of continually griping about, but.... :| )

                            Comment

                            Working...
                            X