问题
I have the following situation:
Interface
public interface Ranged{
public Object getRangeStart();
public Object getRangeEnd();
public void setRangeStart(Object rangeStart);
public void setRangeEnd(Object rangeEnd);
public void setRange(boolean isRange);
public boolean getRange();}
implementing class:
public class CreationDateRange implements Ranged, Serializable{
private static final long serialVersionUID = SerialVersionUID.getSerialVersionUID();
public DateRange()
{
super();
}
private Date dateFrom;
private Date dateTo;
private boolean isRange = false;
public Object getRangeStart()
{
return (Date)dateFrom;
}
public Object getRangeEnd()
{
return (Date)dateTo;
}
public void setRangeStart( Object from )
{
this.dateFrom = (Date)from;
}
public void setRangeEnd( Object to )
{
this.dateTo = (Date)to;
}
public void setRange( boolean isRange )
{
this.isRange = isRange;
}
public boolean getRange()
{
return isRange;
}}
Model:
private Object updateDate = new DateRange();
private Object creationDate = new DateRange();
public void setUpdateDate( Object updateDate )
{
this.updateDate = updateDate;
}
public Object getUpdateDate()
{
return updateDate;
}
public void setCreationDate( Object creationDate )
{
this.creationDate = creationDate;
}
public Object getCreationDate()
{
return creationDate;
}
jsf:
<f:viewParam name="creationDate" value="#{doiListController.model.creationDate}"/>
<f:viewParam name="updateDate" value="#{doiListController.model.updateDate}"/>
...
<td style="font-size: 5pt; border: 0; min-width:60px">
<rich:calendar value="#{listModel.creationDate.rangeStart}"
datePattern="yyyy-MM-dd" enableManualInput="true"
rendered="#{listModel.creationDate.range}">
<f:convertDateTime pattern="yyyy-mm-dd" />
</rich:calendar>
</td>
Error:
>[exec] javax.faces.component.UpdateModelException: javax.el.PropertyNotFoundException: /view/doi/doiListView.xhtml @90,59 value="#{listModel.creationDate.rangeStart}": The cla
ss 'java.lang.String' does not have the property 'rangeStart'.
[exec] at javax.faces.component.UIInput.updateModel(UIInput.java:853)
[exec] at javax.faces.component.UIInput.processUpdates(UIInput.java:735)
[exec] at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
[exec] at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
[exec] at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
[exec] at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1231)
[exec] at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
[exec] at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
[exec] at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
[exec] at javax.faces.webapp.FacesServlet.service(FacesServlet.java:409)
[exec] at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534)
[exec] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
[exec] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
[exec] at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
[exec] at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
[exec] at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
[exec] at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
[exec] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
[exec] at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326)
[exec] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227)
[exec] at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170)
[exec] at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
[exec] at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
[exec] at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
[exec] at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
[exec] at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
[exec] at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
[exec] at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
[exec] at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
[exec] at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
[exec] at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
[exec] at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
[exec] at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
[exec] at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
[exec] at java.lang.Thread.run(Thread.java:619)
[exec] Caused by: javax.el.PropertyNotFoundException: /view/doi/doiListView.xhtml @90,59 value="#{listModel.creationDate.rangeStart}": The class 'java.lang.String' does not ha
ve the property 'rangeStart'.
[exec] at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:133)
[exec] at javax.faces.component.UIInput.updateModel(UIInput.java:818)
[exec] ... 34 more
Can someone help me and say me what am I missing, please?
回答1:
The exception and stacktrace is telling that #{listModel.creationDate}
is actually a String
during the update model values phase of the form submit request.
That can for example happen if something in your view has called listMode.setCreationDate()
with a String
as argument beforehand. For example, by a <f:viewParam>
, <h:inputHidden>
, Converter
-for-class, or whatever else is returning a String
instead of the desired object type.
Put a breakpoint on the setter method and track the root cause down in the stack. Alternatively, you can also replace Object
type by Ranged
type or somehing more specific, so that JSF would possibly throw/display a conversion exception/error which is usually more self-explaining.
回答2:
I found this thread: http://forum.springsource.org/archive/index.php/t-25143.html
Which suggests that JSF may be using your setters (which accept Object
) to set the value as a String.
Why do you hate type saftey?
You should make your fields typed - UpdateDateRange
, CreationDateRange
or at least just Ranged
(why do you have two classes to implement Ranged
? Aren't these just two instances of the same type in two different fields?)
回答3:
As said before, you should introduce types in your model fields (most notably for updateDate and creationDate).
JSF updates the model by converting any string value to the correct type specified in each field. Suppose you have a complex object, then JSF will store this in the session cache (or serialize it, depending on your faces-config.xml) and save it as a hidden attribute in the form.
When you submit the form afterwards, it will try to convert this value back to the correct type. Since the type of this field is Object, it can keep the original String representation and immediately set this field without conversion. If you restrict the type to Ranged, it will try and do the effort to convert the object, and will fail with a correct error message if this does not work.
回答4:
i was facing the same issue. And i found a solution by adding the lazy atribute for dataTable like this.
<p:dataTable lazy="true" var="itemOrder" value="#{orderBean.orderList}">
But i dont understand why.
来源:https://stackoverflow.com/questions/8328577/richcalendar-and-the-class-java-lang-string-does-not-have-the-property