Binding on Spring MVC not working

Asked

Viewed 115 times

3

Well, I have a problem that never occurred to me before related to the Spring MVC Binding.

I have a form as below. The bindind "firstName" and "lastname" work well, but already the "logins.email" troublesome.

<f:form class="form-signin" method="post" action="addAgency" modelAttribute="tenant">

    <div class="input-group">
        <span class="input-group-addon entypo-user"></span>
        <f:input path="firstName" type="text" class="form-control"
            placeholder="Nome" />
    </div>

    <br>

    <div class="input-group">
        <span class="input-group-addon entypo-user"></span>
        <f:input path="lastName" type="text" class="form-control"
            placeholder="Sobrenome" />
    </div>

    <br>

    <div class="input-group">
        <span class="input-group-addon entypo-mail"></span>
        <f:input path="logins.email" type="text" class="form-control"
            placeholder="E-mail" />logins
    </div>

        <!-- Restante de Formulário -->

The Following stackTrace is displayed:

org.springframework.beans.NotReadablePropertyException: Invalid property 'logins.email' of bean class [br.com.joocebox.model.Agency]: Bean property 'logins.email' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
    org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:725)
    org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:716)
    org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
    org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:229)
    org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
    org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
    org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
    org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
    org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:141)
    org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:132)
    org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:116)
    org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
    org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
    org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
    org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
    org.apache.jsp.WEB_002dINF.views.landing.register_jsp._jspx_meth_f_005finput_005f2(register_jsp.java:275)
    org.apache.jsp.WEB_002dINF.views.landing.register_jsp._jspx_meth_f_005fform_005f0(register_jsp.java:138)
    org.apache.jsp.WEB_002dINF.views.landing.register_jsp._jspService(register_jsp.java:77)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:954)
    org.apache.jasper.runtime.PageContextImpl.doInclude(PageContextImpl.java:688)
    org.apache.jasper.runtime.PageContextImpl.include(PageContextImpl.java:682)
    org.apache.tiles.request.jsp.JspRequest.doInclude(JspRequest.java:123)
    org.apache.tiles.request.AbstractViewRequest.dispatch(AbstractViewRequest.java:47)
    org.apache.tiles.request.render.DispatchRenderer.render(DispatchRenderer.java:47)
    org.apache.tiles.request.render.ChainedDelegateRenderer.render(ChainedDelegateRenderer.java:68)
    org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:259)
    org.apache.tiles.template.InsertAttributeModel.renderAttribute(InsertAttributeModel.java:188)
    org.apache.tiles.template.InsertAttributeModel.execute(InsertAttributeModel.java:132)
    org.apache.tiles.jsp.taglib.InsertAttributeTag.doTag(InsertAttributeTag.java:299)
    org.apache.jsp.WEB_002dINF.layouts.landing_jsp._jspx_meth_tiles_005finsertAttribute_005f0(landing_jsp.java:268)
    org.apache.jsp.WEB_002dINF.layouts.landing_jsp._jspService(landing_jsp.java:131)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.apache.tiles.request.servlet.ServletRequest.forward(ServletRequest.java:265)
    org.apache.tiles.request.servlet.ServletRequest.doForward(ServletRequest.java:228)
    org.apache.tiles.request.AbstractClientRequest.dispatch(AbstractClientRequest.java:57)
    org.apache.tiles.request.render.DispatchRenderer.render(DispatchRenderer.java:47)
    org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:259)
    org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:397)
    org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:238)
    org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:221)
    org.apache.tiles.renderer.DefinitionRenderer.render(DefinitionRenderer.java:59)
    org.springframework.web.servlet.view.tiles3.TilesView.renderMergedOutputModel(TilesView.java:114)
    org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
    org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
    org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

Well, the problem is that I have the respective getters and setters in my design. Below are the models of reduced shape:

Agencia.java

@Entity
@Table(name="agency")
@NamedQuery(name="Agency.findAll", query="SELECT a FROM Agency a")
public class Agency implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id_agency")
    private Long idAgency;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(name="subdomain")
    private String subdomain;

    //bi-directional many-to-one association to Login
    @OneToMany(mappedBy="agency")
    private Set<Login> logins;

    public Agency() {
    }

    public Long getIdLogin(){
        return idAgency;
    }

    public void setIdLogin(Long idLogin) {
        this.idAgency = idLogin;
    }

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getSubdomain() {
        return this.subdomain;
    }

    public void setSubdomain(String subdomain) {
        this.subdomain = subdomain;
    }

    public Set<Login> getLogins() {
        return logins;
    }

    public void setLogins(Set<Login> logins) {
        this.logins = logins;
    }

    @Override
    public String toString() {
        return "ID=" + idAgency + ", Sub-Dominio=" + subdomain;
    }

}

Login.java

@Entity
@Table(name="login")
@Multitenant
@TenantDiscriminatorColumn(name="tenant_id", discriminatorType=DiscriminatorType.INTEGER, contextProperty=PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT)
@NamedQuery(name="Login.findAll", query="SELECT l FROM Login l")
public class Login implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id_login")
    private Long idLogin;

    @Column(name="email")
    private String email;

    @Column(name="master")
    private Boolean master;

    @Column(name="password")
    private String password;

    //bi-directional many-to-one association to Agency
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="fk_agency")
    private Agency agency;

    @Enumerated(EnumType.STRING)
    @Column(name="user_role")
    private Role role;

    @Column(name="tenant_id", insertable=false, updatable=false)
    private Long tenantId;

    public Login() {
    }

    public Long getIdLogin() {
        return this.idLogin;
    }

    public void setIdLogin(Long idLogin) {
        this.idLogin = idLogin;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Boolean getMaster() {
        return this.master;
    }

    public void setMaster(Boolean master) {
        this.master = master;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Agency getAgency() {
        return this.agency;
    }

    public void setAgency(Agency agency) {
        this.agency = agency;
    }

    public Long getTenantId() {
        return tenantId;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

}

1 answer

3


Spring MVC won’t do the Binding from a field to a set.

However, if the idea is to receive a comma-separated mailing list, just to quote an example, a simple solution would be to create a Setter who receives a String and uses the split to break into several items by adding them into the set.

In addition, the getter corresponding would join together the elements of the set, separating them by commas, and return the result in a single String.

  • So utluiz, I’m beginning to think that my business rule is wrong, because what I would like is a registration page where new customers would inform a first login and password system, because in the future new users could be registered. Should I do @Onetoone? Thank you

  • 1

    @Joãomanolo It really seems that there are inconsistencies, but without knowing the domain of your system it is very difficult to say the "correct" way, since different situations require different solutions. If you need help, I suggest posting a new conceptual question putting your current model. There are some questions like that around here sometimes and they usually get good answers.

  • 1

    Hi @utluiz. It took me a long time to understand what I was doing here, but I came to the conclusion that I was totally wrong in my approach. After thinking a lot and analyzing some projects found on the web I could make some changes doing so what I would like to have done at first. Of course new problems have now arisen, but this is subject for another post. Thanks and Hugs!

  • @Joãomanolo Legal! Very good to see that you have managed to learn and evolve. Success!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.