Well, I have a problem that has never occurred to me before regarding Spring MVC binding.
I have a form as below. The bindind "firstName" and "lastName" tags work fine, but the "logins.email"
<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 their getters and setters in my project. Below are the reduced form templates:
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;
}
}