Page 1 of 2 12 LastLast
Results 1 to 10 of 17

Thread: How To Install a Property Editor?

  1. #1
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default How To Install a Property Editor?

    Quote Originally Posted by kdonald
    You'll need to install a PropertyEditor to convert from String to Number and vice versa. Unfortunately this doesn't happen automatically yet for the common types. Improving this is a priority.
    Apparently, I need to install a PropertyEditor to convert from String to Number and vice versa so that I don't get a ClassCastException when the framework tries to bind a Form field to an Integer property in a domain object. How and where do I install this PropertyEditor????

    (See http://forum.springframework.org/showthread.php?t=10946 for more details.)
    Last edited by robyn; May 14th, 2006 at 10:43 AM.

  2. #2
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    The SwingFormModel.registerCustomEditor() methods

    CustomNumberEditor, a Spring core class, is what you want.

    Example:

    Code:
                getFormModel().registerCustomEditor(int.class,
                        new CustomNumberEditor(Integer.class, true));
    Keith Donald
    Core Spring Development Team

  3. #3
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default

    Thanks Kieth -- that worked. But is there an easy way to register this custom editor ONLY ONCE and have it apply to ALL instances of SwingFormModel? It's a little bit inconvenient to repeat this registration for every new SwingFormModel.

    I thought I might be able to do this by calling PropertyEditorRegistry.setPropertyEditor() in ApplicationAdvisor.onPostStartup() like this (very ugly, I know):

    Code:
    public class MyApplicationAdvisor extends BeanFactoryApplicationAdvisor {
      ...
    
      public void onPostStartup()
      {
        super.onPostStartup();
        
        getApplication().getApplicationServices().getPropertyEditorRegistry()
          .setPropertyEditor(Number.class, CustomNumberEditor.class);
      }
    }
    However, the call to setPropertyEditor() failed with the exception:
    java.lang.IllegalArgumentException: class org.springframework.beans.propertyeditors.CustomNu mberEditor does not have a no-arg constructor.

    Indeed, CustomNumberEditor does not have a no-arg constructor. Neither do some of the other editors in the package org.springframework.beans.propertyeditors including CustomBooleanEditor, CustomDateEditor and StringTrimmerEditor.

    Is there a better way to do what I'm trying to do?

  4. #4
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    Check out PropertyEditorRegistry :-)
    Keith Donald
    Core Spring Development Team

  5. #5
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default

    Quote Originally Posted by kdonald
    Check out PropertyEditorRegistry :-)
    I thought I did already? :?

    In my previous post, I tried calling PropertyEditorRegistry.setPropertyEditor(Number.cl ass, CustomNumberEditor.class) but I got an IllegalArgumentException because CustomNumberEditor does not have a no-arg constructor. Apparently, some code underneath tries to use reflection to instantiate CustomNumberEditor with a no-arg constructor; obviously, this instantiation will fail.

    Did I overlook some feature of PropertyEditorRegistry?

  6. #6
    Join Date
    Aug 2004
    Location
    Melbourne, Australia
    Posts
    335

    Default

    You need to create a subclass of CustomNumberEditor

    Code:
    class MyIntEditor extends CustomNumberEditor  {
        public MyIntEditor() {
            super(Integer.class, true);
        }
    }
    and then register that class with the PropertyEditorRegistry. You can also configure the PropertyEditorRegistry in your application context.

    Code:
      <bean id="propertyEditorRegistry" 
        class="org.springframework.richclient.application.DefaultPropertyEditorRegistry">
        <property name="propertyEditors">
          <list>
            <props>
              <prop key="objectClass">int</prop>
              <prop key="propertyEditorClass"> MyIntEditor</prop>
            </props>
          </list>
        </property>
      </bean>
    Ollie

  7. #7
    Join Date
    Sep 2004
    Location
    Ghent, Belgium
    Posts
    224

    Default

    updated user documentation on the wiki. Now contains a topic on PropertyEditors (see Forms Support)

  8. #8
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default

    Thanks Ollie and pdbruycker,

    Quote Originally Posted by oliverhutchison
    You need to create a subclass of CustomNumberEditor

    Code:
    class MyIntEditor extends CustomNumberEditor  &#123;
        public MyIntEditor&#40;&#41; &#123;
            super&#40;Integer.class, true&#41;;
        &#125;
    &#125;
    and then register that class with the PropertyEditorRegistry.
    I did try the above PropertyEditorRegistry technique yesterday before I even posted my previous message. But for some reason it didn't work. My editor registered correctly without throwing exceptions but when I tried to call setFormObject() on my Form I got a ClassCastException when the framework tried to set the value of an Integer property into a JTextField that is on the Form:

    Code:
    java.lang.ClassCastException
    	at org.springframework.richclient.forms.AsYouTypeTextValueSetter.setComponentValue&#40;AsYouTypeTextValueSetter.java&#58;50&#41;
    	at org.springframework.richclient.forms.AbstractValueSetter.valueChanged&#40;AbstractValueSetter.java&#58;63&#41;
    	at org.springframework.binding.value.support.AbstractValueModel.fireValueChanged&#40;AbstractValueModel.java&#58;71&#41;
    	at org.springframework.binding.value.support.BufferedValueModel.onWrappedValueChanged&#40;BufferedValueModel.java&#58;82&#41;
    	at org.springframework.binding.value.support.BufferedValueModel$WrappedModelValueChangeHandler.valueChanged&#40;BufferedValueModel.java&#58;70&#41;
    	at org.springframework.binding.value.support.AbstractValueModel.fireValueChanged&#40;AbstractValueModel.java&#58;71&#41;
    	at org.springframework.binding.value.support.PropertyAdapter$DomainObjectChangeHandler.valueChanged&#40;PropertyAdapter.java&#58;70&#41;
    	at org.springframework.binding.value.support.AbstractValueModel.fireValueChanged&#40;AbstractValueModel.java&#58;71&#41;
    	at org.springframework.binding.value.support.ValueHolder.setValue&#40;ValueHolder.java&#58;52&#41;
    	at org.springframework.binding.form.support.AbstractFormModel.setFormObject&#40;AbstractFormModel.java&#58;76&#41;
    	at org.springframework.richclient.forms.SwingFormModel.setFormObject&#40;SwingFormModel.java&#58;269&#41;
    	at org.springframework.richclient.forms.AbstractForm.setFormObject&#40;AbstractForm.java&#58;454&#41;
    	at com.cbconstantini.spring.locationapp.ui.LocationView$2.getSelectedObjectName&#40;LocationView.java&#58;236&#41;
    	at org.springframework.richclient.progress.TreeStatusBarUpdater.onSingleSelection&#40;TreeStatusBarUpdater.java&#58;36&#41;
    	at org.springframework.richclient.tree.TreeSelectionListenerSupport.valueChanged&#40;TreeSelectionListenerSupport.java&#58;49&#41;
    	at javax.swing.JTree.fireValueChanged&#40;JTree.java&#58;2406&#41;
    	at javax.swing.JTree$TreeSelectionRedirector.valueChanged&#40;JTree.java&#58;2777&#41;
    	at javax.swing.tree.DefaultTreeSelectionModel.fireValueChanged&#40;DefaultTreeSelectionModel.java&#58;629&#41;
    	at javax.swing.tree.DefaultTreeSelectionModel.notifyPathChange&#40;DefaultTreeSelectionModel.java&#58;1076&#41;
    	at javax.swing.tree.DefaultTreeSelectionModel.setSelectionPaths&#40;DefaultTreeSelectionModel.java&#58;287&#41;
    	at javax.swing.tree.DefaultTreeSelectionModel.setSelectionPath&#40;DefaultTreeSelectionModel.java&#58;170&#41;
    	at javax.swing.JTree.setSelectionPath&#40;JTree.java&#58;1181&#41;
    	at javax.swing.plaf.basic.BasicTreeUI.selectPathForEvent&#40;BasicTreeUI.java&#58;2192&#41;
    	at javax.swing.plaf.basic.BasicTreeUI$MouseHandler.handleSelection&#40;BasicTreeUI.java&#58;2840&#41;
    	at javax.swing.plaf.basic.BasicTreeUI$MouseHandler.mousePressed&#40;BasicTreeUI.java&#58;2801&#41;
    	at java.awt.AWTEventMulticaster.mousePressed&#40;AWTEventMulticaster.java&#58;218&#41;
    	at java.awt.Component.processMouseEvent&#40;Component.java&#58;5131&#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;3162&#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;
    Note that when I used the other technique (i.e. register a PropertyEditor in the FormModel), setFormObject() worked (i.e. it did NOT throw a ClassCastException) and the Integer field in my domain object was successfully bound to the control on the form. Unfortunately, I would much rather use the PropertyEditorRegistry technique so that I don't have to register my custom integer editor on every single form that is bound to a domain object with an Integer property.

    I'll list the relevant code and bean config below to see if you can figure out what is happening. First, the bean config:

    Code:
    <bean id="propertyEditorRegistry"
    class="org.springframework.richclient.application.support.DefaultPropertyEditorRegistry">
        <property name="propertyEditors">
            <list>
              <props>
                  <prop key="objectClass">java.lang.Integer</prop>
                  <prop key="propertyEditorClass">com.cbconstantini.spring.beans.propertyeditors.CustomIntegerEditor</prop>
              </props>
            </list>
        </property>
    </bean>
    Here's the editor:
    Code:
    package com.cbconstantini.spring.beans.propertyeditors;
    
    import org.springframework.beans.propertyeditors.CustomNumberEditor;
    
    public class CustomIntegerEditor extends CustomNumberEditor
    &#123;
      public CustomIntegerEditor&#40;&#41;
      &#123;
        super&#40;Integer.class, true&#41;;
      &#125;
    &#125;
    Here's the domain object:
    Code:
    package com.cbconstantini.spring.locationapp.domain;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Set;
    
    import org.springframework.beans.support.MutableSortDefinition;
    import org.springframework.beans.support.PropertyComparator;
    
    /**
     * Simple JavaBean domain object representing a Country.
     */
    public class Country extends Entity 
    &#123;
      private String code;
      private String name;
      private Integer longDistanceCode;
      private String phoneNumFmt;
      private Set provinces;
      
      public Integer getLongDistanceCode&#40;&#41;
      &#123;
        return longDistanceCode;
      &#125;
      
      public void setLongDistanceCode&#40;Integer longDistanceCode&#41;
      &#123;
        this.longDistanceCode = longDistanceCode;
      &#125;
    
       // other code omitted
       // ...
    &#125;
    Here's the Form:

    Code:
    package com.cbconstantini.spring.locationapp.ui;
    
    // code omitted
    // ...
    
    public class CountryForm extends AbstractForm &#123;
        public static final String COUNTRY_FORM = "countryForm";
    
        private JComponent name;
    
        public CountryForm&#40;FormModel formModel&#41; &#123;
            super&#40;formModel, COUNTRY_FORM&#41;;
        &#125;
    
        protected JComponent createFormControl&#40;&#41; &#123;
            FormLayout layout = new FormLayout&#40;"left&#58;pref, 5dlu, pref&#58;grow"&#41;;
            BeanFormBuilder formBuilder = new JGoodiesBeanFormBuilder&#40;
                    getFormModel&#40;&#41;, layout&#41;;
            this.name = formBuilder.add&#40;"name"&#41;&#91;1&#93;;
            formBuilder.add&#40;"code"&#41;;
            formBuilder.add&#40;"longDistanceCode"&#41;;
            formBuilder.add&#40;"phoneNumFmt"&#41;;
            return formBuilder.getForm&#40;&#41;;
        &#125;
    
        public boolean requestFocusInWindow&#40;&#41; &#123;
            return name.requestFocusInWindow&#40;&#41;;
        &#125;
    &#125;
    Here's the view where I create the Form and call setFormObject():
    Code:
    public class LocationView extends AbstractView implements ApplicationListener
    &#123;
      private CountryForm countryForm;
      private JTree locationTree;
    
      // code omitted
      // ...
    
      private void createCountryForm&#40;&#41;
      &#123;
        SwingFormModel countryFormModel = SwingFormModel.createFormModel&#40;new Country&#40;&#41;&#41;;
        
    //    countryFormModel.registerCustomEditor&#40;Integer.class,
    //      new CustomIntegerEditor&#40;&#41;&#41;; 
        countryForm = new CountryForm&#40;countryFormModel&#41;;
      &#125;
    
      // code omitted
      // ...
      
      private void createLocationTree&#40;&#41;
      &#123;
        // code omitted
        // ...
        locationTree.addTreeSelectionListener&#40;new TreeStatusBarUpdater&#40;
          getStatusBar&#40;&#41;&#41;
        &#123;
          public String getSelectedObjectName&#40;&#41;
          &#123;
            Object obj = getSelectedNode&#40;&#41;.getUserObject&#40;&#41;;
            if &#40;obj instanceof Country&#41;
            &#123;
              Country country = &#40;Country&#41; obj;
              countryForm.setFormObject&#40;country&#41;; // ClassCastException thrown during this call
              cardLayout.show&#40;cardPanel, COUNTRY_CARD&#41;;
              return country.getName&#40;&#41;;
            &#125;
            else if 
    
        // code omitted
        // ...
      &#125;
    &#125;
    Okay, I think that's all of the relevant code. PLEASE NOTE AGAIN, that when I used the other technique (i.e. register a PropertyEditor in the FormModel), setFormObject() WORKED with the above code (with the countryFormModel.registerCustomEditor() call UNcommented and with the "propertyEditorRegistry" bean config commented, of course).

    For the moment, I'll assume that I have done something incorrectly but to me it looks like there might be a bug somewhere in the framework that is preventing the PropertyEditorRegistry technique from working correctly. I tried tracing the code the figure out what that bug might be but I got a bit lost in the details.

    So, have I done something wrong?

  9. #9
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default

    Ollie, I hope the following will help you narrow down the problem. Here are two stack traces. Both of these stack traces show the stack between where I add the Integer field to the form (i.e. formBuilder.add("longDistanceCode")) and where the Integer field's getter is called on the domain object (i.e. Country.getLongDistanceCode()). The first stack trace uses the "register a PropertyEditor in the FormModel" technique. The second stack trace uses the "PropertyEditorRegistry" technique (which doesn't work for me).

    "register a PropertyEditor in the FormModel" technique
    Code:
    	at com.cbconstantini.spring.locationapp.domain.Country.getLongDistanceCode&#40;Country.java&#58;40&#41;
    	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.beans.BeanWrapperImpl.getPropertyValue&#40;BeanWrapperImpl.java&#58;514&#41;
    	at org.springframework.beans.BeanWrapperImpl.getPropertyValue&#40;BeanWrapperImpl.java&#58;502&#41;
    	at org.springframework.binding.support.BeanPropertyAccessStrategy.getPropertyValue&#40;BeanPropertyAccessStrategy.java&#58;146&#41;
    	at org.springframework.binding.value.support.PropertyAdapter.getValue&#40;PropertyAdapter.java&#58;75&#41;
    	at org.springframework.binding.value.support.BufferedValueModel.getValue&#40;BufferedValueModel.java&#58;128&#41;
    	at org.springframework.binding.value.support.ValueModelWrapper.getValue&#40;ValueModelWrapper.java&#58;39&#41;
    	at org.springframework.binding.value.support.TypeConverter.getValue&#40;TypeConverter.java&#58;90&#41;
    	at org.springframework.binding.value.support.ValueModelWrapper.getValue&#40;ValueModelWrapper.java&#58;39&#41;
    	at org.springframework.richclient.forms.SwingFormModel.bind&#40;SwingFormModel.java&#58;562&#41;
    	at org.springframework.richclient.forms.SwingFormModel.bind&#40;SwingFormModel.java&#58;555&#41;
    	at org.springframework.richclient.forms.SwingFormModel.createBoundTextField&#40;SwingFormModel.java&#58;502&#41;
    	at org.springframework.richclient.forms.SwingFormModel.createBoundControl&#40;SwingFormModel.java&#58;431&#41;
    	at org.springframework.richclient.form.builder.AbstractFormBuilder.getDefaultComponent&#40;AbstractFormBuilder.java&#58;62&#41;
    	at org.springframework.richclient.forms.JGoodiesBeanFormBuilder.add&#40;JGoodiesBeanFormBuilder.java&#58;62&#41;
    	at com.cbconstantini.spring.locationapp.ui.CountryForm.createFormControl&#40;CountryForm.java&#58;30&#41;
    "PropertyEditorRegistry" technique
    Code:
    	at com.cbconstantini.spring.locationapp.domain.Country.getLongDistanceCode&#40;Country.java&#58;40&#41;
    	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.beans.BeanWrapperImpl.getPropertyValue&#40;BeanWrapperImpl.java&#58;514&#41;
    	at org.springframework.beans.BeanWrapperImpl.getPropertyValue&#40;BeanWrapperImpl.java&#58;502&#41;
    	at org.springframework.binding.support.BeanPropertyAccessStrategy.getPropertyValue&#40;BeanPropertyAccessStrategy.java&#58;146&#41;
    	at org.springframework.binding.value.support.PropertyAdapter.getValue&#40;PropertyAdapter.java&#58;75&#41;
    	at org.springframework.binding.value.support.BufferedValueModel.getValue&#40;BufferedValueModel.java&#58;128&#41;
    	at org.springframework.binding.value.support.ValueModelWrapper.getValue&#40;ValueModelWrapper.java&#58;39&#41;
    	at org.springframework.richclient.forms.SwingFormModel.bind&#40;SwingFormModel.java&#58;562&#41;
    	at org.springframework.richclient.forms.SwingFormModel.bind&#40;SwingFormModel.java&#58;555&#41;
    	at org.springframework.richclient.forms.SwingFormModel.createBoundTextField&#40;SwingFormModel.java&#58;502&#41;
    	at org.springframework.richclient.forms.SwingFormModel.createBoundControl&#40;SwingFormModel.java&#58;431&#41;
    	at org.springframework.richclient.form.builder.AbstractFormBuilder.getDefaultComponent&#40;AbstractFormBuilder.java&#58;62&#41;
    	at org.springframework.richclient.forms.JGoodiesBeanFormBuilder.add&#40;JGoodiesBeanFormBuilder.java&#58;62&#41;
    	at com.cbconstantini.spring.locationapp.ui.CountryForm.createFormControl&#40;CountryForm.java&#58;30&#41;
    My expectation was that both stack traces would be exactly the same. However, note that the first stack trace has the following two extra lines, otherwise they are the same:
    Code:
    	at org.springframework.binding.value.support.TypeConverter.getValue&#40;TypeConverter.java&#58;90&#41;
    	at org.springframework.binding.value.support.ValueModelWrapper.getValue&#40;ValueModelWrapper.java&#58;39&#41;
    Again, as I noted in my previous post, my code is exactly the same in both cases except for the actual property editor registration.

  10. #10

    Default

    Maybe you misconfigure something?

Similar Threads

  1. Order of Bean definitions matters?
    By cfuser in forum Container
    Replies: 2
    Last Post: Oct 21st, 2005, 10:29 AM
  2. Unit testing with JOTM and JtaTransactionManager
    By lalle in forum Architecture
    Replies: 1
    Last Post: Oct 15th, 2005, 09:05 AM
  3. EHCaching Hibernate
    By dencamel in forum Data
    Replies: 3
    Last Post: Sep 6th, 2005, 09:03 PM
  4. Replies: 4
    Last Post: Aug 17th, 2005, 04:42 AM
  5. Replies: 2
    Last Post: May 13th, 2005, 05:42 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •