PDA

View Full Version : Problem faced in Spring MVC Portlet in the implementation of parent and child relatio


sureshck
May 18th, 2007, 11:07 AM
Following is the explanation of the problem faced in Spring MVC Portlet.

Parent – Survey

Child – SurveyUser (Relation one to many with Survey)

The implementation is master detail.

We are able to Insert/update and retrieve with the parent.

We are able to retrieve the data from child but unable to update/insert.



Following is the Parent Pojo –



private String surveyId;

private Site site;

private String name;

private String description;

private Date surveyDate;

private Long correctTracking;

private String completionUrl;

private String imageUrl;

private String authorName;

private Set<SurveyUser> surveyUsers;



Child is a Set object in parent.



HBM –



<set name="surveyUsers" inverse="true" cascade="all">

<key column="SURVEY_ID"/>

<one-to-many class="com.cmp.cms.model.SurveyUser" />

</set>



JSP Code –



<c:forEach var="no" items="${survey.surveyUsers}" varStatus="s">

<tr>

<td style="text-align: right">

<spring:bind path="survey.surveyUsers[${s.index}].userSurveyId">

<input type="text" name="${status.expression}" value="${status.value}"/>

</td>

</spring:bind>

<td style="text-align: right">

<spring:bind path="survey.surveyUsers[${s.index}].userId">

<input type="text" name="${status.expression}" value="${status.value}" size="30"/>

<span class="fieldError">${status.errorMessage}</span>

</spring:bind>

</td>

<td>

<spring:bind path="survey.surveyUsers[${s.index}].userSurveyDate">

<input type="text" name="${status.expression}" value="${status.value}" size="15"/>

<span class="fieldError">${status.errorMessage}</span>

</spring:bind>

</td>

</tr>



</c:forEach>



Note : We are getting the data from database but unable to insert/update the child.



initBinder method implementation –



SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy hh:mm");

binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, true));

NumberFormat nf = NumberFormat.getNumberInstance();



binder.registerCustomEditor(Long.class, null, new CustomNumberEditor(Long.class, nf, true));

binder.registerCustomEditor(Site.class, "site.siteId", new PropertyEditorSupport(new Site()));

binder.registerCustomEditor(Set.class, null, new CustomCollectionEditor(SurveyUser.class, true));



String key = request.getParameter("workType");

if("ADD".equals(key)) {

binder.setAllowedFields(new String[] {"surveyId","site.siteId","name","description","surveyDate","correctTracking","completionUrl","imageUrl","authorName","surveyUsers.userSurveyId","surveyUsers.userId","surveyUsers.userSurveyDate"});

} else {

binder.setAllowedFields(new String[] {"surveyId","name","description","surveyDate","correctTracking","completionUrl","imageUrl","authorName","surveyUsers.userSurveyId","surveyUsers.userId","surveyUsers.userSurveyDate"});

}

binder.bind(request);



We are not sure is it binding the child object.



formBackingObject method implementation –



Survey survey;

String key = request.getParameter("surveyId");

if(("".equals(key) || (key==null))) {

survey = new Survey();

} else {

survey = service.findEntrysByPK(key);

}
return survey;

Should we need to add anything here…
Please advice…
We are not getting any error but the changed value is not updating to child table.

Thanks and Best Regards,

Suresh

sureshck
May 22nd, 2007, 05:34 AM
Please anyone help me to resolve the problem..

Marten Deinum
May 22nd, 2007, 05:43 AM
when posting code PLEASE PLEASE PLEASE use the [ code][ /code] tags. It makes your code so much easier to read.

One thing that makes me wonder is this line especially the highlighted part.


binder.registerCustomEditor(Set.class, null, new CustomCollectionEditor(SurveyUser.class, true));


it should read something like the line below, you should specify the type of collection the CustomCollectionEditor should create. If you want to do something special extend the CustomCollectionEditor and override/implement the convertElement (http://www.springframework.org/docs/api/org/springframework/beans/propertyeditors/CustomCollectionEditor.html#convertElement(java.la ng.Object)) method.


binder.registerCustomEditor(Set.class, null, new CustomCollectionEditor(HashSet.class, true));


Also you shouldn't be calling 'binder.bind(request)' yourself, let spring handle it, remove that line or call super.initBinder.

sureshck
May 22nd, 2007, 07:35 AM
Thanks for the response. Sorry for not using , I am a new user:) , in future i will use the same.

I have added

binder.registerCustomEditor(Set.class, "surveyUsers", new CustomCollectionEditor(HashSet.class,true));


Here my child column is surveyUsers.
I getting exception:
ERROR [jsp:52] java.lang.NoSuchMethodError: org.springframework.beans.propertyeditors.CustomCo llectionEdit
or.<init>(Ljava/lang/Class;Z)V

If i remove true parameter in the CustomCollectionEditor() method I am not getting the exception but if I change the child in my view its not updating.

Please advice...
Thanks once again.

Marten Deinum
May 22nd, 2007, 07:40 AM
Which version of Spring are you using? It appears that the version in your classpath is different from the one in your servlet container. You probably have 2 versions of the spring.jar in your classpath.

Did you also remove the binder.bind part from the initBinder method? The binding should really be done by Spring and not yourself.

sureshck
May 22nd, 2007, 07:58 AM
Thanks for your reply.
I have removed binder.bind last time itself.
I have got only one version in my classpath.

Please help me in getting the child object for insertion.

Jsp

<tr>
<td style="text-align: right">
<html:input path="survey.surveyUsers.userSurveyId" rows="20" cols="20"/>
</td>
<td style="text-align: right">
<html:input path="survey.surveyUsers.userId" rows="20" cols="20"/>
</td>
<td>
<html:input path="survey.surveyUsers.userSurveyDate" rows="20" cols="20"/>
</td>
</tr>


How to give the child pojo name and its attribute.
Here survey is parent pojo
Child is surveyUsers. -> Pojo is SurveyUser
Child is a Set object in my parent pojo.
Please help me to understand.

sureshck
May 22nd, 2007, 10:13 AM
Please help me....
I am using Spring2.

Please help me I am new to Spring MVC portlet.

Jörg Heinicke
May 22nd, 2007, 06:44 PM
<tr>
<td style="text-align: right">
<html:input path="survey.surveyUsers.userSurveyId" rows="20" cols="20"/>
</td>
<td style="text-align: right">
<html:input path="survey.surveyUsers.userId" rows="20" cols="20"/>
</td>
<td>
<html:input path="survey.surveyUsers.userSurveyDate" rows="20" cols="20"/>
</td>
</tr>

How to give the child pojo name and its attribute.
Here survey is parent pojo
Child is surveyUsers. -> Pojo is SurveyUser
Child is a Set object in my parent pojo.
Please help me to understand.

Please help me to understand. :)

What do you want to reach? To create one <tr> for every surveyUser in your set? You can use standard JSTL <c:forEach>.

Jörg

sureshck
May 23rd, 2007, 01:41 AM
Thanks for your reply.

For retrieving I am doing the loop.
How should i assign surveyUser for adding in the screen.
Please look into the below jsp code:

<fmt:bundle basename="messages">
<form method="post" action="<portlet:actionURL>
<portlet:param name="workType" value="<%=request.getParameter("workType")%>"/>
<portlet:param name="action" value="sign"/>
</portlet:actionURL>">
<html:errors path="survey" fields="true"/>
<%=request.getParameter("workType")%>
<c:set var='namespace'><portlet:namespace/></c:set>
<fieldset>
<c:set var="temp" value="ADD" />
<c:set var="checkVal" value="<%=request.getParameter("workType")%>" />
<c:choose>
<c:when test="${checkVal==temp}">
<legend><fmt:message key='legend.sign'/></legend>
</c:when>
<c:otherwise>
<legend><fmt:message key='legend.mod'/></legend>
</c:otherwise>
</c:choose>
<label for="${namespace}surveyId"><fmt:message key='label.surveyId'/></label>
<html:input path="survey.surveyId" size="20"/><br/>
<label for="${namespace}site.siteId"><fmt:message key='label.siteId'/></label>
<html:input path="survey.site.siteId" size="20"/><br/>
<label for="${namespace}name"><fmt:message key='label.name'/></label>
<html:input path="survey.name" size="20"/><br/>
<label for="${namespace}description"><fmt:message key='label.description'/></label>
<html:input path="survey.description" size="20"/><br/>
<label for="${namespace}surveyDate"><fmt:message key='label.surveyDate'/></label>
<c:set var='datepattern'><fmt:message key='time.pattern'/></c:set>
<fmt:formatDate value='${survey.surveyDate}' pattern='${datepattern}' var='surDate'/>
<html:input path="survey.surveyDate" size="20" value="${surDate}"/><br/>
<label for="${namespace}correctTracking"><fmt:message key='label.correctTracking'/></label>
<html:input path="survey.correctTracking" size="20"/><br/>
<label for="${namespace}completionUrl"><fmt:message key='label.completionUrl'/></label>
<html:input path="survey.completionUrl" rows="20" cols="20"/><br/>
<label for="${namespace}imageUrl"><fmt:message key='label.imageUrl'/></label>
<html:input path="survey.imageUrl" rows="20" cols="20"/><br/>
<label for="${namespace}authorName"><fmt:message key='label.authorName'/></label>
<html:input path="survey.authorName" rows="20" cols="20"/><br/>
<table>
<tr>
<th style="text-align: left">Survey Id</th>
<th style="text-align: left">User Id</th>
<th style="text-align: left">Survey Date</th>
</tr>
<c:forEach var="no" items="${survey.surveyUsers}" varStatus="s">
<tr>
<td style="text-align: right">
<spring:bind path="survey.surveyUsers[${s.index}].userSurveyId">
<input type="text" name="${status.expression}" value="${status.value}"/>
</td>
</spring:bind>
<td style="text-align: right">
<spring:bind path="survey.surveyUsers[${s.index}].userId">
<input type="text" name="${status.expression}" value="${status.value}" size="30"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
<td>
<spring:bind path="survey.surveyUsers[${s.index}].userSurveyDate">
<input type="text" name="${status.expression}" value="${status.value}" size="15"/>
<span class="fieldError">${status.errorMessage}</span>
</spring:bind>
</td>
</tr>

</c:forEach>

</table>
<button type="submit"><fmt:message key="label.button.sign"/></button>

</fieldset>
</fmt:bundle>


Here I am getting the surveyUser data from database but I change the data its not updating to command class Survey.

My controller class


public class AddEntrySurveyController extends SimpleFormController implements InitializingBean {

protected SurveyService service;


public void setSurveyService(SurveyService service) {
this.service = service;
}

public void afterPropertiesSet() throws Exception {
if (this.service == null)
throw new IllegalArgumentException("A SurveyService is required");
}


public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
Survey survey = (Survey) command;
String stat;
stat = request.getParameter("workType");
if (stat.equals("ADD")) {

service.saveEntry(survey);
} else {
service.saveUpdateEntry(survey);
}
System.out.println("workType="+request.getParameter("workType"));
response.setRenderParameter("workType", request.getParameter("workType"));
response.setRenderParameter("action","list");
}


protected Object formBackingObject(PortletRequest request)
throws Exception {
Survey survey;
String key = request.getParameter("surveyId");
if(("".equals(key) || (key==null))) {
survey = new Survey();
Set<SurveyUser> sruset = new HashSet();
} else {
survey = service.findEntrysByPK(key);
}

return survey;
}


protected void initBinder(PortletRequest request, PortletRequestDataBinder binder)
throws Exception {

SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy hh:mm");
binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, true));
NumberFormat nf = NumberFormat.getNumberInstance();

binder.registerCustomEditor(Long.class, null, new CustomNumberEditor(Long.class, nf, true));
binder.registerCustomEditor(Site.class, "site.siteId", new PropertyEditorSupport(new Site()));
binder.registerCustomEditor(Set.class, "surveyUsers", new CustomCollectionEditor(HashSet.class,true));
//binder.registerCustomEditor(SurveyUser.class, "surveyUsers", new CustomCollectionEditor(Set.class));
String key = request.getParameter("workType");
request.setAttribute("workType", request.getParameter("workType"));
if("ADD".equals(key)) {
binder.setAllowedFields(new String[] {"surveyId","site.siteId","name","description","surveyDate","correctTracking","completionUrl","imageUrl","authorName","surveyUsers"});
} else {
binder.setAllowedFields(new String[] {"surveyId","name","description","surveyDate","correctTracking","completionUrl","imageUrl","authorName","surveyUsers"});
}
//binder.bind(request);
}

protected ModelAndView renderInvalidSubmit(RenderRequest request, RenderResponse response)
throws Exception {
return null;
}

protected void handleInvalidSubmit(ActionRequest request, ActionResponse response)
throws Exception {
response.setRenderParameter("workType", request.getParameter("workType"));
response.setRenderParameter("action","list");
}
}


Please advice where I am wrong....

sureshck
May 23rd, 2007, 07:36 AM
Please help me.

Marten Deinum
May 23rd, 2007, 07:52 AM
binder.registerCustomEditor(Site.class, "site.siteId", new PropertyEditorSupport(new Site()));
binder.registerCustomEditor(Set.class, "surveyUsers", new CustomCollectionEditor(HashSet.class,true));

Why do you always create a new Site() object for the site.siteId, the Id property looks like an long/int to me and not a Site object.

Have you tried attaching a debugger to your code to see what is happening. Simply calling (help me) each day isn't going to help you solve your problem.

sureshck
May 23rd, 2007, 08:49 AM
Thanks for your reply
I was checking the flow.

We are able to retrieve the data of the child SurveyUser from database.
We are unable to update/insert the data to child.
If we alter the child in controller class (hard-coding some values for testing) it is getting saved.
The problem is the command class is not updating with the child.
We are unable to bind the child to command class.:(

sureshck
May 25th, 2007, 09:31 AM
Any update for the problem:(

Jörg Heinicke
May 25th, 2007, 11:03 AM
Sorry, but that was too hard to follow. You probably just lost us.

Jörg