Wednesday, February 23, 2011

Typical Security in Roo (#springroo, #roo-typical-security)

Rohit Ghatol, the author of the typical security addon for Spring Roo has invited me to be a contributor.

So my first contribution was to fix the minor bugs I mentioned in my previous post.

The following are reflected in the 0.1.4.BUILD-SNAPSHOT of the typical security addon:

  1. Password encryption
  2. Fixed SimpleMailMessage Autowire bug in SignUpController.java and ForgotPasswordController.java
  3. Fixed activationDate
  4. Fixed the finders 
  5. Renamed UserModel to User and RoleModel to Role.
  6. Renamed the Typicalsecurity command to typicalsecurity
  7. Set the default entity package to ~.domain (to align with how the rest of roo works).
As always, both Rohit and I welcome your feedback on this tool.

Saturday, February 19, 2011

Typical Security in roo

Roo provides a basic Spring Security setup out of the box.
roo> security setup
But what if you want the typical security features like user registration and password changing etc.?

There is a project underway to provide this. The Typical security add-on for roo facilitates the generation of some typical security features.

The author introduced it to the community here: http://forum.springsource.org/showthread.php?t=100534 but basically, the following will be all that you need to do to gain all the typical security features.
roo> Typicalsecurity setup --controllerPackage ~.web --entityPackage ~.domain
There are some minor bugs in the current build (0.1.2.BUILD). After you run the setup, you will need to
roo> focus --class ~.domain.UserModel
~.domain.UserModel roo> finder add findUserModelsByEmailAddress
~.domain.UserModel roo> finder add findUserModelsByActivationKeyAndEmailAddress
~.domain.UserModel roo> field date --type java.util.Date --fieldName activationDate
~.domain.UserModel roo> focus --class ~.domain.UserRoleModel
~.domain.UserRoleModel roo> finder add findUserRoleModelsByUserEntry
and you will need to comment out the Autowired annotation for SimpleMailMessage in SignUpController.java and ForgotPasswordController.java
//@Autowired
private transient SimpleMailMessage simpleMailMessage;

I will be keeping a close eye on this project. I sure hope it finds its way into the standard roo distribution.

Saturday, February 5, 2011

In Context Creation of Related Objects

As I stated in my last blog post, I have been looking into solutions for ROO-207 "Allow in context creation of 1:n and 1:1 related objects". Well, I am happy to announce that I am getting there. What I have now can best be described as an early work-around. It's not a full solution, but rather a first kick at it.

The direction I'm currently going with is to change as little of the look and feel of ROO as possible. To that end, I will leave the drop down list of related items for now. I am also using Dojo for this since it is already included by ROO.

What I've done is always display the "add" icon beside the dropdown list of referenced items. Clicking on that icon launches a modal dialog box with all the fields required to create a new Object. When that modal form is submitted, the values are saved using JSON. Clicking the down arrow in the dropdown list fetches the latest Objects using JSON. There are some known issues with this solution, such as:
  1. There is no validation on the dialog form.
  2. Since it is extremely manual, it is still very error prone.
  3. If you change anything on the referenced Object, you will have to change the create page for the host Object.
  4. We fetch the latest objects every time the referenced Object list is opened. This may be an un-acceptable performance hit.
I'm publishing this work to gather the opinions of the community before going through the effort of turning this into a plugin.

A picture says a thousand words... so here are a couple thousand words.
Petclinic - Add Pet Add "Owner" from within "Add Pet" screen.

There were a few new files created

  • clinic/src/main/webapp/WEB-INF/tags/util/
    • json-util.tagx
      This file contains the JavaScript that handles the display of the dialog, the dynamic linking of the Owners select tag to the database, and the saving of the dialog form.
    • link-to-json.tagx
      This tag links the form element defined to the database though JavaScript calls to functions defined in the above file.
  • clinic/src/main/webapp/WEB-INF/tags/form
    • create-json.tagx
      This tag is based on the create.tagx in the same folder, but instead of a basic <form>, a modal dialog is created.

...and some others that just needed to be modified.

  • clinic/src/main/java/com/springsource/petclinic/domain
    • Owner.java
      Not absolutely necessary, but I added a "getName()" method so that the dropdown would display the full name of the owner.
  • clinic/src/main/webapp/WEB-INF/tags/util/
  • clinic/src/main/webapp/WEB-INF/tags/form/
    • create.tagx
      Modified since the host form was not getting submitted while the referred form was on the page.
  • clinic/src/main/webapp/WEB-INF/tags/form/fields/
    • select.tagx
      Modified to accommodate the selective inline creation of Objects.
    • textarea.tagx
      Modified to support the disabling of form binding.
  • clinic/src/main/webapp/WEB-INF/views/pets/
    • create.jspx
      Modified to include the Owner creation form.

The high level steps that are required to execute this in a clean application are:

  1. Generate the clean application.
  2. Enable JSON for the referenced objects.
  3. Copy the new and modified files.
  4. Modify the Create page for the host Objects.

Details of the changes

  1. Generate the clean application.

    roo> script --file clinic.roo
  2. Enable JSON for the referenced objects.

    roo> json add --class ~.domain.Owner
  3. Copy the new and modified files.

    Click on the file names above to download them from my server and save them into the source path indicated. (If you prefer, just download the new files and follow these instructions to modify the existing files.)

    Owner.java

    package com.springsource.petclinic.domain;

    import org.springframework.roo.addon.entity.RooEntity;
    import org.springframework.roo.addon.javabean.RooJavaBean;
    import org.springframework.roo.addon.tostring.RooToString;
    import java.util.Set;
    import com.springsource.petclinic.domain.Pet;
    import java.util.HashSet;
    import javax.persistence.OneToMany;
    import javax.persistence.CascadeType;
    import javax.persistence.Transient;

    import org.springframework.roo.addon.json.RooJson;

    @RooJavaBean
    @RooToString
    @RooEntity
    @RooJson
    public class Owner extends AbstractPerson {

        @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
        private Set<Pet> pets = new HashSet<Pet>();

        public String getName(){
         return getFirstName() + " " + getLastName();
        }

    }


    load-scripts.tagx (enable Dojo's "parseOnLoad")

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
      <jsp:output omit-xml-declaration="yes" />
      <spring:theme code="styleSheet" var="roo_css" />
      <spring:url value="/${roo_css}" var="roo_css_url" />
      <spring:url value="/resources/dojo/dojo.js" var="dojo_url" />
      <spring:url value="/resources/dijit/themes/tundra/tundra.css" var="tundra_url" />
      <spring:url value="/resources/spring/Spring.js" var="spring_url" />
      <spring:url value="/resources/spring/Spring-Dojo.js" var="spring_dojo_url" />
      <spring:url value="/resources/images/favicon.ico" var="favicon" />
      <link rel="stylesheet" type="text/css" media="screen" href="${roo_css_url}"><!-- required for FF3 and Opera --></link>
      <link rel="stylesheet" type="text/css" href="${tundra_url}"><!-- required for FF3 and Opera --></link>
      <link rel="SHORTCUT ICON" href="${favicon}" />
      <!-- Get the user local from the page context (it was set by Spring MVC's locale resolver) -->
      <c:set var="userLocale">
        <c:out value="${pageContext.response.locale}" default="en" />
      </c:set>
      <script type="text/javascript">var djConfig = {parseOnLoad: false, isDebug: false, locale: '${fn:toLowerCase(userLocale)}'};</script>

      <script src="${dojo_url}" djConfig="parseOnLoad: true, isDebug: true" type="text/javascript"><!-- required for FF3 and Opera --></script>
      <script src="${spring_url}" type="text/javascript"><!-- /required for FF3 and Opera --></script>
      <script src="${spring_dojo_url}" type="text/javascript"><!-- required for FF3 and Opera --></script>
      <script language="JavaScript" type="text/javascript">dojo.require("dojo.parser");</script>
    </jsp:root>

    create.tagx

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
      <jsp:output omit-xml-declaration="yes"/>
      <jsp:directive.attribute name="id" type="java.lang.String" required="true" description="The identifier for this tag (do not change!)"/>
      <jsp:directive.attribute name="modelAttribute" type="java.lang.String" required="true" description="The name of the model attribute for form binding"/>
      <jsp:directive.attribute name="path" type="java.lang.String" required="true" description="Specify the relative URL path (wit leading /)" />
      <jsp:directive.attribute name="label" type="java.lang.String" required="false" description="The label used for this object, will default to a message bundle if not supplied"/>
      <jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
      <jsp:directive.attribute name="openPane" type="java.lang.Boolean" required="false" description="Control if the title pane is opened or closed by default (default: true)"/>
      <jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)"/>

      <c:if test="${empty render or render}">
        <c:if test="${empty label}">
          <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
        </c:if>
        <spring:message arguments="${label}" code="entity_create" var="title_msg"/>
        <util:panel id="${id}" title="${title_msg}" openPane="${openPane}">
          <spring:url value="${path}" var="form_url"/>
          <form:form action="${fn:escapeXml(form_url)}" method="POST" modelAttribute="${modelAttribute}">
            <form:errors cssClass="errors" delimiter="&lt;p/&gt;"/>
            <jsp:doBody />
            <div class="submit" id="${fn:escapeXml(id)}_submit">
              <spring:message code="button_save" var="save_button"/>
              <script type="text/javascript">Spring.addDecoration(new Spring.ValidateAllDecoration({elementId:'proceed', event:'onclickonsubmit'}));</script>
              <input id="proceed" type="submit" value="${fn:escapeXml(save_button)}"/>
            </div>
          </form:form>
        </util:panel>
      </c:if>
    </jsp:root>

    select.tagx

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
      <jsp:output omit-xml-declaration="yes" />

      <jsp:directive.attribute name="id" type="java.lang.String" required="true" description="The identifier for this tag (do not change!)" />
      <jsp:directive.attribute name="field" type="java.lang.String" required="true" description="The field exposed from the form backing object" />
      <jsp:directive.attribute name="path" type="java.lang.String" required="true" description="The relative path to the referenced resource" />
      <jsp:directive.attribute name="items" type="java.util.Collection" required="true" description="The name of the collection displayed in the select box" />
      <jsp:directive.attribute name="label" type="java.lang.String" required="false" description="The label used for this field, will default to a message bundle if not supplied" />
      <jsp:directive.attribute name="itemValue" type="java.lang.String" required="false" description="The identifier used as value in the select box (defaults to 'id' for non enum types)" />
      <jsp:directive.attribute name="required" type="java.lang.Boolean" required="false" description="Indicates if this field is required (default false)" />
      <jsp:directive.attribute name="disabled" type="java.lang.Boolean" required="false" description="Specify if this field should be enabled" />
      <jsp:directive.attribute name="multiple" type="java.lang.Boolean" required="false" description="Specify if the select box should allow multiple selections" />
      <jsp:directive.attribute name="disableFormBinding" type="java.lang.Boolean" required="false" description="Set to true to disable Spring form binding" />
      <jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
      <jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)" />
      <jsp:directive.attribute name="inlineCreate" type="java.lang.Boolean" required="false" description="Indicate if this object can be created inline (default 'false')" />

      <c:if test="${empty render or render}">

        <c:if test="${empty disabled}">
          <c:set value="false" var="disabled" />
        </c:if>

        <c:if test="${empty label}">
          <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
        </c:if>

        <c:if test="${empty required}">
          <c:set value="false" var="required" />
        </c:if>

        <c:if test="${empty multiple}">
          <c:set value="false" var="multiple" />
        </c:if>
      
        <c:set var="sec_field">
          <spring:escapeBody javaScriptEscape="true" >${field}</spring:escapeBody>
        </c:set>

        <div id="_${fn:escapeXml(id)}_id">
          <c:choose>
            <c:when test="${not empty items or inlineCreate}">
              <label for="_${sec_field}_id">
                <c:out value="${fn:escapeXml(label)}" />
                :
              </label>
              <c:choose>
                <c:when test="${empty itemValue}">
                  <c:choose>
                    <c:when test="${disableFormBinding}">
                      <select id="_${sec_field}_id" name="${sec_field}" multiple="${multiple}">
                        <c:forEach items="${items}" var="item">
                          <option value="${item}">
                            <spring:eval expression="item" />
                          </option>
                        </c:forEach>
                      </select>
                    </c:when>
                    <c:otherwise>
                      <form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" multiple="${multiple}" />
                      <br />
                      <form:errors cssClass="errors" id="_${sec_field}_error_id" path="${sec_field}" />
                    </c:otherwise>
                  </c:choose>
                </c:when>
                <c:otherwise>
                  <c:choose>
                    <c:when test="${disableFormBinding}">
                      <select id="_${sec_field}_id" name="${sec_field}" multiple="${multiple}">
                        <c:forEach items="${items}" var="item">
                          <option value="${item[fn:escapeXml(itemValue)]}">
                            <spring:eval expression="item" />
                          </option>
                        </c:forEach>
                      </select>
                    </c:when>
                    <c:otherwise>
                      <form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" multiple="${multiple}" itemValue="${fn:escapeXml(itemValue)}" />
                      <br />
                      <form:errors cssClass="errors" id="_${sec_field}_error_id" path="${sec_field}" />
                    </c:otherwise>
                  </c:choose>
                </c:otherwise>
              </c:choose>
              <c:if test="${inlineCreate}">
    <spring:url value="/resources/images/add.png" var="create_img_url" />
    <spring:message arguments="${label}" code="global_menu_new" var="add_message" />
    <img onclick="showCreateDialog('${sec_field}');" alt="${fn:escapeXml(add_message)}" src="${fn:escapeXml(create_img_url)}" title="${fn:escapeXml(add_message)}" />
     </c:if>
     <br />

              <c:choose>
                <c:when test="${multiple == false}">
                  <script type="text/javascript">Spring.addDecoration(new Spring.ElementDecoration({elementId : '_${sec_field}_id', widgetType: 'dijit.form.FilteringSelect', widgetAttrs : {hasDownArrow : true}})); </script>
                </c:when>
                <!-- disabled due to http://jira.springframework.org/browse/ROO-909 <c:otherwise> <script type="text/javascript">Spring.addDecoration(new Spring.ElementDecoration({elementId : '_${field}_id', widgetType: 'dijit.form.MultiSelect', widgetAttrs : {}})); </script> </c:otherwise> -->
              </c:choose>
            </c:when>
            <c:otherwise>
              <field:reference field="${label}" id="${id}" path="${path}" required="${required}" />
            </c:otherwise>
          </c:choose>
        </div>
        <br />

      </c:if>
    </jsp:root>

    textarea.tagx

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
      <jsp:output omit-xml-declaration="yes" />

      <jsp:directive.attribute name="id" type="java.lang.String" required="true" description="The identifier for this tag (do not change!)" />
      <jsp:directive.attribute name="field" type="java.lang.String" required="true" description="The field exposed from the form backing object" />
      <jsp:directive.attribute name="label" type="java.lang.String" required="false" description="The label used for this field, will default to a message bundle if not supplied" />
      <jsp:directive.attribute name="required" type="java.lang.Boolean" required="false" description="Indicates if this field is required (default false)" />
      <jsp:directive.attribute name="disabled" type="java.lang.Boolean" required="false" description="Specify if this field should be enabled" />
      <jsp:directive.attribute name="validationRegex" type="java.lang.String" required="false" description="Specify regular expression to be used for the validation of the input contents" />
      <jsp:directive.attribute name="validationMessageCode" type="java.lang.String" required="false" description="Specify the message (message property code) to be displayed if the regular expression validation fails" />
      <jsp:directive.attribute name="validationMessage" type="java.lang.String" required="false" description="Specify the message to be displayed if the regular expression validation fails" />
      <jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
      <jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)" />
      <jsp:directive.attribute name="disableFormBinding" type="java.lang.Boolean" required="false" description="Set to true to disable Spring form binding" />

      <c:if test="${empty render or render}">

        <c:if test="${empty disabled}">
          <c:set value="false" var="disabled" />
        </c:if>

        <c:if test="${empty label}">
          <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
        </c:if>

        <c:if test="${empty required}">
          <c:set value="false" var="required" />
        </c:if>
      
        <c:set var="sec_field">
          <spring:escapeBody javaScriptEscape="true" >${field}</spring:escapeBody>
        </c:set>

        <script type="text/javascript">dojo.require("dijit.form.SimpleTextarea");</script>
        <div id="_${fn:escapeXml(id)}_id">
          <label for="_${sec_field}_id">
            <c:out value="${fn:escapeXml(label)}" />
            :
          </label>
          <c:choose>
            <c:when test="${disableFormBinding}">
         <textarea id="_${sec_field}_id" name="${sec_field}">${sec_field}</textarea>
            </c:when>
            <c:otherwise>

         <form:textarea id="_${sec_field}_id" path="${sec_field}" disabled="${disabled}" />
       </c:otherwise>
     </c:choose>

          <br />
          <form:errors cssClass="errors" id="_${sec_field}_error_id" path="${sec_field}" />
          <script type="text/javascript">Spring.addDecoration(new Spring.ElementDecoration({elementId : '_${sec_field}_id', widgetType : 'dijit.form.SimpleTextarea', widgetAttrs : {disabled : ${disabled}}})); </script>
        </div>
        <br />

      </c:if>
    </jsp:root>

  4. Modify the Create page for the host Objects.

    This last step has three sub-steps. Again in our example, we want to create an Owner from within the page that we use to create a Pet.
    1. Copy the creation form from the "create Owner" page. (clinic/src/main/webapp/WEB-INF/views/owners/create.jspx)
    2. Paste it into the "create Pets" page. (clinic/src/main/webapp/WEB-INF/views/pets/create.jspx)
    3. We will then modify it.

    create.jspx (Owners - copy)

    ...
        <form:create id="fc_com_springsource_petclinic_domain_Owner" modelAttribute="owner" path="/owners" render="${empty dependencies}" z="JVL6ZvtbnTyvO3flv+5gP4Lf98o=">
            <field:input field="firstName" id="c_com_springsource_petclinic_domain_Owner_firstName" max="30" min="3" z="iFQbgU5/QXNtac+P4ovg8kEV7ek="/>
            <field:input field="lastName" id="c_com_springsource_petclinic_domain_Owner_lastName" max="30" min="3" required="true" z="njvl6BTK6olS0lu0xpz2JAljl/w="/>
            <field:textarea field="address" id="c_com_springsource_petclinic_domain_Owner_address" required="true" z="F58lrymQYAb+vI2R18H+u5MV3co="/>
            <field:input field="city" id="c_com_springsource_petclinic_domain_Owner_city" max="30" required="true" z="KeFguNGWsgzbj3W5t5xAQ67nB8w="/>
            <field:input field="telephone" id="c_com_springsource_petclinic_domain_Owner_telephone" required="true" z="UArcYWJhCMGb8fdNhd+tPR7lGZA="/>
            <field:input field="homePage" id="c_com_springsource_petclinic_domain_Owner_homePage" max="30" z="/vNZCeUDVvKka/dick16UkqxCeM="/>
            <field:input field="email" id="c_com_springsource_petclinic_domain_Owner_email" max="30" min="6" validationMessageCode="field_invalid_email" z="OBipoi4fQlmRIdM78qa1WWEIIwU="/>
            <field:datetime dateTimePattern="${owner_birthday_date_format}" field="birthDay" id="c_com_springsource_petclinic_domain_Owner_birthDay" required="true" z="hePNmv60SdPIC9BHED+b/A3wvL8="/>
            <field:simple field="pets" id="c_com_springsource_petclinic_domain_Owner_pets" messageCode="entity_reference_not_managed" messageCodeAttribute="Pet" z="mFNdxgNw45XzY+L48hMYPWM8B4E="/>
        </form:create>
    ...

    create.jspx (Pets - paste)

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">

        <jsp:directive.page contentType="text/html;charset=UTF-8"/>
        <jsp:output omit-xml-declaration="yes"/>
        <form:create id="fc_com_springsource_petclinic_domain_Pet" modelAttribute="pet" path="/pets" render="${empty dependencies}" z="lgvEyAlAYOudDmaPjwU0ABseTIk=">
            <field:checkbox field="sendReminders" id="c_com_springsource_petclinic_domain_Pet_sendReminders" z="uPpMX+IWb0KONpvd11fpG8x4/4Q="/>
            <field:input field="name" id="c_com_springsource_petclinic_domain_Pet_name" min="1" required="true" z="ZY+k75JeSo9RmejYZRFNIvs2aBg="/>
            <field:input field="weight" id="c_com_springsource_petclinic_domain_Pet_weight" min="0" required="true" validationMessageCode="field_invalid_number" z="cOD5zE/z7gy+RZu5kVSPuxCa+/I="/>
            <field:select field="owner" inlineCreate="true" id="c_com_springsource_petclinic_domain_Pet_owner" itemValue="id" items="${owners}" path="/owners" z="fGzswAP4XXvhPhowJKsRVve929c="/>
            <field:select field="type" id="c_com_springsource_petclinic_domain_Pet_type" items="${pettypes}" path="pettypes" required="true" z="+hDCnUp+Y+A1RlT+AjH07sgipOo="/>
        </form:create>
        <form:dependency dependencies="${dependencies}" id="d_com_springsource_petclinic_domain_Pet" render="${not empty dependencies}" z="kThDNIW+69h9nI/69ynY1WyUieo="/>
      

        <form:create id="fc_com_springsource_petclinic_domain_Owner" modelAttribute="owner" path="/owners" render="${empty dependencies}" z="JVL6ZvtbnTyvO3flv+5gP4Lf98o=">
            <field:input field="firstName" id="c_com_springsource_petclinic_domain_Owner_firstName" max="30" min="3" z="iFQbgU5/QXNtac+P4ovg8kEV7ek="/>
            <field:input field="lastName" id="c_com_springsource_petclinic_domain_Owner_lastName" max="30" min="3" required="true" z="njvl6BTK6olS0lu0xpz2JAljl/w="/>
            <field:textarea field="address" id="c_com_springsource_petclinic_domain_Owner_address" required="true" z="F58lrymQYAb+vI2R18H+u5MV3co="/>
            <field:input field="city" id="c_com_springsource_petclinic_domain_Owner_city" max="30" required="true" z="KeFguNGWsgzbj3W5t5xAQ67nB8w="/>
            <field:input field="telephone" id="c_com_springsource_petclinic_domain_Owner_telephone" required="true" z="UArcYWJhCMGb8fdNhd+tPR7lGZA="/>
            <field:input field="homePage" id="c_com_springsource_petclinic_domain_Owner_homePage" max="30" z="/vNZCeUDVvKka/dick16UkqxCeM="/>
            <field:input field="email" id="c_com_springsource_petclinic_domain_Owner_email" max="30" min="6" validationMessageCode="field_invalid_email" z="OBipoi4fQlmRIdM78qa1WWEIIwU="/>
            <field:datetime dateTimePattern="${owner_birthday_date_format}" field="birthDay" id="c_com_springsource_petclinic_domain_Owner_birthDay" required="true" z="hePNmv60SdPIC9BHED+b/A3wvL8="/>
            <field:simple field="pets" id="c_com_springsource_petclinic_domain_Owner_pets" messageCode="entity_reference_not_managed" messageCodeAttribute="Pet" z="mFNdxgNw45XzY+L48hMYPWM8B4E="/>
        </form:create>


    </div>


    create.jspx (Pets - modify)


    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">

        <util:json-util />
        <util:link-to-json field="owner" itemValue="id" path="/owners" />

        <jsp:directive.page contentType="text/html;charset=UTF-8"/>
        <jsp:output omit-xml-declaration="yes"/>
        <form:create id="fc_com_springsource_petclinic_domain_Pet" modelAttribute="pet" path="/pets" render="${empty dependencies}" z="lgvEyAlAYOudDmaPjwU0ABseTIk=">
            <field:checkbox field="sendReminders" id="c_com_springsource_petclinic_domain_Pet_sendReminders" z="uPpMX+IWb0KONpvd11fpG8x4/4Q="/>
            <field:input field="name" id="c_com_springsource_petclinic_domain_Pet_name" min="1" required="true" z="ZY+k75JeSo9RmejYZRFNIvs2aBg="/>
            <field:input field="weight" id="c_com_springsource_petclinic_domain_Pet_weight" min="0" required="true" validationMessageCode="field_invalid_number" z="cOD5zE/z7gy+RZu5kVSPuxCa+/I="/>
            <field:select field="owner" inlineCreate="true" id="c_com_springsource_petclinic_domain_Pet_owner" itemValue="id" items="${owners}" path="/owners" z="fGzswAP4XXvhPhowJKsRVve929c="/>
            <field:select field="type" id="c_com_springsource_petclinic_domain_Pet_type" items="${pettypes}" path="pettypes" required="true" z="+hDCnUp+Y+A1RlT+AjH07sgipOo="/>
        </form:create>
        <form:dependency dependencies="${dependencies}" id="d_com_springsource_petclinic_domain_Pet" render="${not empty dependencies}" z="kThDNIW+69h9nI/69ynY1WyUieo="/>
      
        <form:create-json id="fc_com_springsource_petclinic_domain_Owner" modelAttribute="owner" path="/petclinic/owners/jsonArray" render="${empty dependencies}" z="JVL6ZvtbnTyvO3flv+5gP4Lf98o=">
            <field:input field="firstName" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_firstName" max="30" min="3" z="iFQbgU5/QXNtac+P4ovg8kEV7ek="/>
            <field:input field="lastName" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_lastName" max="30" min="3" required="true" z="njvl6BTK6olS0lu0xpz2JAljl/w="/>
            <field:textarea field="address" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_address" required="true" z="F58lrymQYAb+vI2R18H+u5MV3co="/>
            <field:input field="city" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_city" max="30" required="true" z="KeFguNGWsgzbj3W5t5xAQ67nB8w="/>
            <field:input field="telephone" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_telephone" required="true" z="UArcYWJhCMGb8fdNhd+tPR7lGZA="/>
            <field:input field="homePage" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_homePage" max="30" z="/vNZCeUDVvKka/dick16UkqxCeM="/>
            <field:input field="email" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_email" max="30" min="6" validationMessageCode="field_invalid_email" z="OBipoi4fQlmRIdM78qa1WWEIIwU="/>
            <field:datetime dateTimePattern="MM/dd/yyyy" field="birthDay" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_birthDay" required="true" z="hePNmv60SdPIC9BHED+b/A3wvL8="/>
            <field:simple field="pets" id="c_com_springsource_petclinic_domain_Owner_pets" messageCode="entity_reference_not_managed" messageCodeAttribute="Pet" z="mFNdxgNw45XzY+L48hMYPWM8B4E="/>
        </form:create-json>

    </div>