Announcement Announcement Module
Collapse
No announcement yet.
Map based form model Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Map based form model

    Is it possible to have a map backed form model? I would like to capture search criteria as a map with keys being property names and pass it further down to hibernate. I do not want to create a separate bean for every search form - hence the map idea.

    I am a total newbie in Spring RCP, so pardon my question if the answer is trivial.

  • #2
    Just looked into this for myself today. Yes, it is possible...damn Spring Rich rocks. For my test I created a form object with a map, to make it quick and easy I just overrode Rectangle.

    Code:
    public class MyRect extends Rectangle {
    
      private Map<String, Color> colors;
    
      public Map<String, Color> getColors() {
        return colors;
      }
    
      public void setColors(Map<String, Color> colors) {
        this.colors = colors;
      }
    
      public MyRect() {
        super(0, 0, 50, 100);
        colors = new HashMap<String, Color>();
        colors.put("red", Color.RED);
        colors.put("blue", Color.BLUE);
        colors.put("cyan", Color.CYAN);
      }
    
    }
    I then created a view to display my test form. To create the form model I just called FormModelHelper.createFormModel(r). The other methods seem to work as well. In my form's #createFormControl() method I bound my map to the controls like this.

    Code:
    @Override
    protected JComponent createFormControl() {
      SwingBindingFactory bf = (SwingBindingFactory)getBindingFactory();
      FormLayout layout = new FormLayout("pref, $lcgap, pref",
          "pref, $pgap, default:grow");
      MyFormBuilder builder = new MyFormBuilder(bf, layout);
      builder.setLabelAttributes(FormLayoutFormBuilder.ALIGN_RIGHT_CENTER);
    
      builder.addTextAreaAndLabel("colors[red]", 1, 1);
      builder.nextRow();
    
      builder.addComponent(createButtonBar());
    
      return builder.getPanel();
    }
    Of course for this example to work I needed to create a pair of converters to convert ColorToString and StringToColor.

    Code:
    public class ColorToString extends AbstractFormattingConverter {
    
      private final boolean allowEmpty;
    
      /**
       * Creates a new instance of <code>ColorToString</code>.
       */
      public ColorToString() {
        this(new SimpleFormatterFactory(), true);
      }
    
      /**
       * Creates a new instance of <code>ColorToString</code>.
       */
      public ColorToString(FormatterFactory formatterFactory, boolean allowEmpty) {
        super(formatterFactory);
        this.allowEmpty = allowEmpty;
      }
    
      @Override
      protected Object doConvert(Object source, Class type, ConversionContext cc) throws Exception {
        Color color = (Color)source;
        return (!allowEmpty || source != null)
            ? color.getRed() + "," + color.getGreen() + "," + color.getBlue() : null;
      }
    
      @Override
      public Class[] getSourceClasses() {
        return new Class[] {Color.class};
      }
    
      @Override
      public Class[] getTargetClasses() {
        return new Class[] {String.class};
      }
    
    }
    
    public class StringToColor extends AbstractFormattingConverter {
    
      private final boolean allowEmpty;
      
      /**
       * Creates a new instance of <code>StringToColor</code>.
       */
      public StringToColor() {
        this(new SimpleFormatterFactory(), true);
      }
    
      /**
       * Creates a new instance of <code>StringToColor</code>.
       */
      public StringToColor(FormatterFactory formatterFactory, boolean allowEmpty) {
        super(formatterFactory);
        this.allowEmpty = allowEmpty;
      }
    
      @Override
      protected Color doConvert(Object source, Class type, ConversionContext cc) throws Exception {
        String[] parts = ((String)source).split(",");
        return (!allowEmpty || source != null) ? new Color(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2])) : null;
      }
    
      @Override
      public Class[] getSourceClasses() {
        return new Class[] {String.class};
      }
    
      @Override
      public Class[] getTargetClasses() {
        return new Class[] {Color.class};
      }
    
    }
    and configure my conversion service to use the new converters in the application context.

    Code:
    <bean id="conversionService" class="org.springframework.richclient.application.DefaultConversionServiceFactoryBean" />
      <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" >
      <property name="targetObject" ref="conversionService" />
      <property name="targetMethod" value="addConverters" />
      <property name="arguments">
        <list>
          <list>
            <bean class="org.my.app.converter.ColorToString" />
            <bean class="org.my.app.converter.StringToColor" />
          </list>
        </list>
      </property>
    </bean>
    This should allow you to bind controls to a map, although I have not yet tested what happens if the property does not exist in the map.

    Comment

    Working...
    X