Spring MVC - Auto generating names of Model attributes

[Updated: Jan 11, 2017, Created: Jan 11, 2017]

A Model instance can add objects without any specified name by using following methods:

Model addAttribute(Object attributeValue)
Model addAllAttributes(Collection<?> attributeValues)

Model object auto generates attribute names and then forward the above method calls to addAttribute(String attributeName, Object attributeValue)



Following are the rules of name generation strategy:

  • For an object which is not a collection, short class name is generated. For example for java.lang.String, 'string' will be generated.
  • For collections/arrays, 'List' is appended after the type of elements in it e.g. 'stringList'. The collection/array should not be empty because the logic uses the first element to find it's type.


Example


@Controller
public class TheController {

    @RequestMapping("/")
    public String handleRequest (Model model) {
        String string1 = "my string value";
        model.addAttribute(string1);

        int i = 10;
        model.addAttribute(i);

        List<String> list = Arrays.asList("one", "two");
        model.addAttribute(list);
        return "myView";
    }
}

myView.jsp
 <%@ page language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="fm"%>

<html>
  <body style="margin:15px;">

      <p>String value: ${string}</p>
      <p>int value: ${integer}</p>
      <br/>
      StringList:
      <fm:checkboxes path="stringList" items="${stringList}" />

  </body>
</html>


Output




If, in a single Model, same object type is being populated various times then we should use explicit attribute name rather than relying on auto name generation.

Some developer would prefer to use explicit names anyways, so that they have more control on attribute names. It's good to use this feature in simple cases though.



The logic of name generation is actually forwarded to the Conventions#getVariableName(..). Here's a test to understand auto generation rules:

public class VariableNameTest {
    public static void main (String[] args) {

        Object obj = "test string";
        print(obj, "\"test string\"");

        obj = new String[]{"one", "two"};
        print(obj, "new String[]{\"one\", \"two\"};");

        obj = 5;
        print(obj, "5");

        obj = new Integer(5);
        print(obj, "new Integer(5)");

        obj = 'z';
        print(obj, "'z'");

        obj = Arrays.asList(1, 2, 3);
        print(obj, "Arrays.asList(1, 2, 3)");

        obj = new LinkedList<>(Arrays.asList(1, 2, 3));
        print(obj, "new LinkedList<>(Arrays.asList(1, 2, 3))");

        obj = new HashSet<>(Arrays.asList("1", "2"));
        print(obj, "new HashSet<>(Arrays.asList(\"1\", \"2\"))");

        obj = new HashMap<String, Integer>();
        print(obj, "new HashMap<String, Integer>()");

        obj = new LinkedHashMap<>();
        print(obj, "new LinkedHashMap<>()");

        obj = new TreeMap<>();
        print(obj, "new TreeMap<>()");

        obj = new MyNestedObject();
        print(obj, "MyNestedObject()");

        obj = new TheController();
        print(obj, "new TheController()");

        //a collection cannot be empty (map is ok)
        // following will throw IllegalArgumentException,
       /* Set<Integer> integerTreeSet = new TreeSet<>();
        name = Conventions.getVariableName(integerTreeSet);
        print("Set<Integer> integerTreeSet = new TreeSet<>();", name);*/

    }

    private static void print (Object obj, String declaration) {
        String name = Conventions.getVariableName(obj);
        System.out.printf("%40s: %s%n", declaration, name);
    }

    private static class MyNestedObject {
    }
}

Output

                            "test string": string
              new String[]{"one", "two"};: stringList
                                        5: integer
                           new Integer(5): integer
                                      'z': character
                   Arrays.asList(1, 2, 3): integerList
 new LinkedList<>(Arrays.asList(1, 2, 3)): integerList
   new HashSet<>(Arrays.asList("1", "2")): stringList
           new HashMap<String, Integer>(): hashMap
                    new LinkedHashMap<>(): linkedHashMap
                          new TreeMap<>(): treeMap
                         MyNestedObject(): myNestedObject
                      new TheController(): theController




Example Project

Dependencies and Technologies Used :

  • spring-boot-starter-web 1.4.3.RELEASE: Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container.
    Corresponding Spring version: 4.3.5.RELEASE
  • tomcat-embed-jasper 8.5.6: Core Tomcat implementation.
  • JDK 1.8
  • Maven 3.3.9

Model Attribute Name Generation Select All Download
  • model-attribute-generated-names
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
        • webapp
          • WEB-INF
            • pages

See Also