Announcement Announcement Module
Collapse
No announcement yet.
Binding HashMap attribute to HTML form Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Binding HashMap attribute to HTML form

    Greetings,

    I've been working on this thing for days, now, and so far, haven't reached any progress, yet.

    I have a Class that has a HashMap attribute, and I need to bind it to an HTML form, somehow

    The thing is, I have no clue on how to do the whole thing!

    I do know how to do a Form-backing, but I do not know how to do the way back, when I'm supposed to save the changes. I have no clue on how to retrieve the data from the form and use it with the binder/property editor.

    I'm using SimpleFormController and was intending on using CustomCollectionEditor.

    Any ideas ?

    Thanks!

    Renato Back

  • #2
    Are you just wanting to display the contents of the HashMap on the htmp/jsp? Or is your html/jsp submitting the HashMap to the form?

    If you just want to display...

    I have a jsp on which I want to display a few collections (Maps, Lists) and a few other data types (some custom actually). This sounds kinda like what you want.

    I'm using a SimpleFormController as my controller type. SimpleFormController has a method
    Code:
    protected Map referenceData(HttpServletRequest request) throws ServletException;
    . In that method you do what you need.
    <snip>
    Map elements = new HashMap();
    elements.add("somelist", aList);
    elements.add("someMap", aMap);
    </snip>

    In your jsp you can then just reference the elements by ${someList}, etc.

    Comment


    • #3
      I do know...

      Hey there Travis,

      I do know how to retrieve the information from the controller.
      My problem is exactly in sending it back after the user has included, altered or erased data at the html form.

      Got the picture ?

      Thanks,

      Renato Back

      Comment


      • #4
        Ah, ok. In your doSubmit the "Object command" that gets sent is your POJO which backs the form. You can do custom editors to define how to handle various types. I found this link which contains an example of using the CustomCollectionEditor: http://www.jroller.com/page/raible?e...ith_spring_mvc.

        Wish I could help more.

        Comment


        • #5
          Hey there, Travis!

          I already tried the CustomCollectionEditor, but as far as I could check, it only handles Collections.

          I did find a possible solution.
          I extended PropertyEditorSupport and adapted the CustomCollection to use Map instead of Collection.

          So far, so good. I was able to create, delete and retrieve data. But I haven't got any good results when trying to update data.

          I'm still running some tests, so as soon as I get them, I'll post here if it works or not hehehe.

          Thanks again for the help,

          Renato Back

          Comment


          • #6
            Howdy, people!

            I figured out the solution a while back ago, but forgot to post it here.
            Basically, I had to extend PropertyEditorSupport and create (copy and change names) methods that would deal with Map instances instead of Collection.
            So here it goes. It's kinda messy, but it works just fine for me.

            Code:
            import java.beans.PropertyEditorSupport;
            import java.lang.reflect.Array;
            import java.util.HashMap;
            import java.util.Map;
            import java.util.Set;
            import java.util.StringTokenizer;
            
            import org.hibernate.collection.PersistentMap;
            import org.springframework.core.CollectionFactory;
            
            public class ParameterMapEditor extends PropertyEditorSupport
            {
            
                private final Class mapType;
            
                public ParameterMapEditor(Class mapType)
                {
                    if (mapType == null)
                    {
                        throw new IllegalArgumentException("Map type is required");
                    }
                    if (!Set.class.isAssignableFrom(mapType))
                    {            
                        if (!Map.class.isAssignableFrom(mapType))
                        {
                            throw new IllegalArgumentException("Map type [" + mapType.getName() + "] does not implement [java.util.Map]");
                        }
                    }
                    this.mapType = mapType;
                }
            
                @SuppressWarnings("unchecked")
                public void setValue(Object value)
                {
                    if (value == null)
                    {
                        super.setValue(createMap(this.mapType, 0));
                    }
            
                    else if (this.mapType.isInstance(value))
                    {
                        super.setValue(value);
                    }
                    else if (value instanceof PersistentMap)
                    {
                        Map source = (PersistentMap) value;
                        Map target = createMap(this.mapType, source.size());
                        
                        target.putAll((Map) convertElement(value));
                        
                        super.setValue(target);
                    }
                    else if (value instanceof Map)
                    {
                        Map source = (Map) value;
                        Map target = createMap(this.mapType, source.size());
            
                        target.putAll((Map) convertElement(source));
            
                        super.setValue(target);
                    }
                    else if (value.getClass().isArray())
                    {
                        Map target = (Map) convertElement(value);
                        
                        super.setValue(target);
                    }
                    else
                    {
                        Map target = createMap(this.mapType, 1);
                        Map convertedSource = (Map) convertElement(value);
            
                        target.putAll(convertedSource);
            
                        super.setValue(target);
                    }
                }
            
                protected Map createMap(Class collectionType, int initialCapacity)
                {
                    if (!collectionType.isInterface())
                    {
                        try
                        {
                            return (Map) collectionType.newInstance();
                        }
                        catch (Exception ex)
                        {
                            throw new IllegalArgumentException("Could not instantiate map class [" + collectionType.getName() + "]: " + ex.getMessage());
                        }
                    }
                    else
                    {
                        return CollectionFactory.createLinkedMapIfPossible(initialCapacity);
                    }
                }
            
                @SuppressWarnings("unchecked")
                protected Object convertElement(Object element)
                {
                    Map<String, String> aux = new HashMap<String, String>(0);
                    
                    if (element.getClass().isArray())
                    {
                        int tamanhoLista;
                        tamanhoLista = Array.getLength(element);
                        aux = new HashMap<String, String>(tamanhoLista);
                        
                        StringTokenizer st;
                        for (int i = 0; i < tamanhoLista; i++)
                        {
                            st = new StringTokenizer(String.valueOf(Array.get(element, i)), "#");
                            aux.put(st.nextToken(), st.nextToken());
                        }
                    }
                    else if (element instanceof String)
                    {
                        aux = new HashMap<String, String>(1);
                        StringTokenizer st = new StringTokenizer((String)element, "#");
                        aux.put(st.nextToken(), st.nextToken());
                    }
                    else 
                    {
                        Class[] classes = element.getClass().getInterfaces();
                        for (Class class1 : classes)
                        {
                            if (class1.equals(Map.class))
                            {
                                aux.putAll( (Map<String, String>) element );
                            }
                            
                        }
                    }
            
                    return aux;
                }
                
                public void setAsText(String text) throws IllegalArgumentException 
                {
                    setValue(text);
                }
                
                public String getAsText() 
                {
                    return null;
                }
            
            }
            Thanks for the attention,

            Regards,

            Renato Back

            Comment


            • #7
              Lifesaver

              Hey there!

              The post has been dead for some time now, but you're a lifesaver.
              Thanks for contributing your code.

              Oh, and of course i'm doing something wrong here... How do you bind the hashmap in your jsp form?

              My code is:
              --------------------------------
              <spring:bind path="hashmap">
              <c:forEach var="parameter" items="${status.value}">
              <tr><td class="label"><c:out value="${parameter.key}"/></label></td>
              <td class="value"><input type="text" name="${status.expression}" value="${parameter.value}" /></td>
              </tr></c:forEach>
              </spring:bind>
              ---------------------

              And my exception when i post the form:

              ---------------------
              java.util.NoSuchElementException
              at java.util.StringTokenizer.nextToken(Unknown Source)
              at foo.bar.ParameterMapEditor.convertElement(Paramete rMapEditor.java:143)
              ---------------------



              Cheers and happycoding

              Bjarne
              Last edited by Bjarne; Nov 3rd, 2007, 11:43 AM.

              Comment


              • #8
                Salut!

                Dear Bjarne,

                As you said, this topic has been dead for quite a while, still, I'm glad you found some use out of this mess hehe
                I haven't used this code in a while, and after reviewing it, I'd do some major changes and use some different approaches. I'll see if I can implement those later on.

                JSP bind sample
                Code:
                <spring:bind path="parameters">
                	<td colspan="4">
                		<input type="hidden" name="_<c:out value="${status.expression}"/>" value="visible" />
                		<select name="<c:out value="${status.expression}"/>" multiple="multiple" size="10" style="width: 100%;" ${disabled} >
                			<c:forEach items="${status.value}" var="parameter">
                				<option value="${parameter.key}#${parameter.value}" selected="selected">${parameter.key} = ${parameter.value}</option>
                			</c:forEach>
                		</select>
                	</td>
                	<td>
                		<input type="button" name="edit" value="Editar" onClick="editParameterComposto(form1.parameters, form1.parameterName, form1.parameterValor)" ${disabled} />
                		<br />
                		<input type="button" name="delete" value="Excluir" onClick="deleteSimples(form1.parameters)" ${disabled} />
                	</td>
                </spring:bind>
                OK, so here's the thing, I'm not sure the problem is in the JSP mapping, instead I think there might be some problem at your controller mapping. Here are some sample mappings for the controller and for the propertyEditor:

                Controller mapping
                Code:
                	<!-- Bean that controls CRUD operations for Link items -->
                <bean name="/linkManager" class="br.com.supportcomm.next.spring.controller.GenericCRUDFormController">
                	<property name="successView" value="forward:/admin/linkList" />
                	<property name="formView" value="/linkForm.jsp" />
                	<property name="sessionForm" value="true" />
                	<property name="commandName" value="link" />
                	<property name="commandClass" value="br.com.supportcomm.next.portal.Link" />
                 	<property name="validator" ref="linkValidator" />
                	<property name="dependencies">
                		<list>
                			<ref bean="portalDependency" />
                		</list>
                	</property>
                	<property name="customEditors">
                		<list>
                			<ref bean="parameterMapEditor" />
                		</list>
                	</property>
                	<property name="dao" ref="linkDAOHibernate" />
                </bean>
                Property Editor
                Code:
                	<!-- Bean that handles the binding of a String[name#value] to a HashMap -->
                <bean id="parameterMapEditor" class="br.com.supportcomm.next.core.CustomPropertyEditor">
                	<property name="customEditor" value="br.com.supportcomm.next.spring.propertyeditor.ParameterMapEditor" />
                	<property name="collectionType" value="java.util.HashMap" />
                	<property name="propertyName" value="parameters" />
                </bean>
                Keep in mind that the propertyName value in the parameterMapEditor mapping has to be the same as the property you're trying to map. For example, an object:

                ______________
                | Object |
                |---------------| Has to have a propertyName value of "prop".
                |prop : HashMap|
                |_____________|

                There is a number of ways you can do this, but the one I used that time was this one

                I hope it helps!
                Please keep me updated.

                Regards,

                Renato Back
                Last edited by renatopb; Nov 5th, 2007, 05:38 AM. Reason: Forgot the JSP sample code xD

                Comment

                Working...
                X